当我们进行业务开发的时候,通常都是需要暴露 HTTP 端口给前端页面进行调用。当我们使用 Spring Boot 进行 Web 业务开发的时候只需要引入以下 starter 依赖:
spring web 依赖 starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
引入了 spring-boot-starter-web 这个 starter 依赖,它会引入 tomcat 嵌入式容器。当我们使用 main 方法启动项目的时候它会内部启动 Tomcat 容器。这样我们就可以访问暴露的 restful 服务了。比如:
@RestController
@SpringBootApplication
public class Bootstrap {
public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
@GetMapping("test")
public String test() {
return "hello, world";
}
}
然后我们可以访问:http://localhost:8080/test 这个地址就可以返回 hello, world字符串。

这个是因为 Tomcat 默认使用的是 8080 这个端口.其实不管是默认的 Tomcat 容器还是 Jetty 或者 Undertow。Spring Boot 都对它们进行了抽象,可以通过 ServletWebServerFactory 来获取到 WebServer。根据 classpath 中看 jar 包是依赖了 Tomcat、Jetty 或者 Undertow 来创建不同的容器。比如如果不使用 Tomcat 而想使用 Undertow,需要在 spring-boot-starter-web 这个 starter 当中排除 spring-boot-starter-tomcat 然后依赖 spring-boot-starter-undertow。如下所示:
使用 Undertow 为 Web 容器
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
</dependencies>
从下面的启动日志当中我们就可以看出它是以 Undertow 这个 Web 容器来启动的。关于容器切换具体的原理可以参考我的另一篇博客 - Spring Boot 自动配置原理解析

从上面的章节当中,我们可以看到 Spring Boot 在启动容器的时候默认通过 8080 来暴露 http 服务的。如果我们需要指定暴露 http 服务的端口,我们应该怎么做呢?其实可以通过下面几种方式来指定我们暴露的 http 服务端口。
我们可以在配置文件当中通过 server.port 来指定我们服务启动暴露的端口。
application.properties
server.port=8888
启动控制台,日志如下所示:

它的实现原理如下:
[server.port] ->
ServerProperties ->
ServletWebServerFactoryCustomizer ->
ConfigurableWebServerFactory ->
TomcatServletWebServerFactory
Spring 项目当中,可以通过 ServletWebServerFactory 来获取到 WebServer.Tomcat 的实现类是 TomcatServletWebServerFactory。在这个对象里面,可以通过 tomcatConnectorCustomizers 属性它是一个 Set<TomcatConnectorCustomizer> 。TomcatConnectorCustomizer 可以指定容器启动暴露的端口。
自定义 TomcatConnectorCustomizer
@Bean
public TomcatConnectorCustomizer customServerPortTomcatConnectorCustomizer() {
return connector -> connector.setPort(8888);
}
启动控制台,日志如下所示:

TomcatServletWebServerFactory 不仅仅实现了 ServletWebServerFactory ,同时他也实现了WebServerFactory。而且 Spring Boot 来提供了 WebServerFactoryCustomizer 这个接口来定制化WebServerFactory, TomcatServletWebServerFactory同时也是实现了WebServerFactory的子接口 ConfigurableWebServerFactory。这个接口是可以对 WebServer 进行配置化,包括 Web 容器的端口。
自定义 WebServerFactoryCustomizer
@Bean
public WebServerFactoryCustomizer customServerPortWebServerFactoryCustomizer() {
return factory -> {
if (factory instanceof ConfigurableWebServerFactory) {
ConfigurableWebServerFactory webServerFactory = ConfigurableWebServerFactory.class.cast(factory);
webServerFactory.setPort(8888);
}
};
}
启动控制台,日志如下所示:

其实自定义 WebServerFactoryCustomizer 它的起始类是通过 WebServerFactoryCustomizerBeanPostProcessor 来进行自定义 WebServerFactory。具体的代码逻辑如下:

我们也可以模仿它通过自定义 BeanPostProcess 来自定义 Web 容器暴露的端口。
自定义 BeanPostProcessor
@Bean
public BeanPostProcessor customServerPortBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof ConfigurableWebServerFactory) {
ConfigurableWebServerFactory webServerFactory = ConfigurableWebServerFactory.class.cast(bean);
webServerFactory.setPort(8888);
}
return bean;
}
};
}
启动控制台,日志如下所示:

在 Idea 工具中添加项目请求参数: --server.port=8888,如下所示:

启动控制台,日志如下所示:

它的实现原理是通过:org.springframework.boot.SpringApplication#configurePropertySources 把请求参数添加到 Spring 对环境变量的抽象 Environment 当中,然后通过以下方式把 server.port 设置到 Tomcat 容器当中:
把 Environment 值设置 Tomcat 的 port
- ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
把 Environment 中的 [server.port] 绑定到 ServerProperties 这个 bean 当中
- ServletWebServerFactoryCustomizer#customize
把 ServerProperties 的 port 设置到 Tomcat 当中
- AbstractConfigurableWebServerFactory#setPort
在 Idea 工具中添加系统变量: -Dserver.port=8888,如下所示:

然后在 org.springframework.boot.SpringApplication#prepareEnvironment 调用 getOrCreateEnvironment() 之后,查看 environment,通过如下公式获取 ConfigurableEnvironment 对象中的 server.port
environment.getPropertySources().get("systemProperties").getProperty("server.port")
如下所示:

然后通过以下方式把 server.port 设置到 Tomcat 容器当中:
把 Environment 值设置 Tomcat 的 port
- ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
把 Environment 中的 [server.port] 绑定到 ServerProperties 这个 bean 当中
- ServletWebServerFactoryCustomizer#customize
把 ServerProperties 的 port 设置到 Tomcat 当中
- AbstractConfigurableWebServerFactory#setPort
以上就是博主现在已知的修改Spring Boot 项目启动指定 HTTP 端口的几种方式。
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat