当我们进行业务开发的时候,通常都是需要暴露 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 服务端口。

1、配置文件

我们可以在配置文件当中通过 server.port 来指定我们服务启动暴露的端口。

application.properties

server.port=8888

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

在这里插入图片描述
它的实现原理如下:

[server.port] -> 
ServerProperties -> 
ServletWebServerFactoryCustomizer ->
ConfigurableWebServerFactory -> 
TomcatServletWebServerFactory

2、自定义 TomcatConnectorCustomizer

Spring 项目当中,可以通过 ServletWebServerFactory 来获取到 WebServer.Tomcat 的实现类是 TomcatServletWebServerFactory。在这个对象里面,可以通过 tomcatConnectorCustomizers 属性它是一个 Set<TomcatConnectorCustomizer>TomcatConnectorCustomizer 可以指定容器启动暴露的端口。

自定义 TomcatConnectorCustomizer

@Bean
public TomcatConnectorCustomizer customServerPortTomcatConnectorCustomizer() {
    return connector -> connector.setPort(8888);
}

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

在这里插入图片描述

3、自定义 WebServerFactoryCustomizer

TomcatServletWebServerFactory 不仅仅实现了 ServletWebServerFactory ,同时他也实现了WebServerFactory。而且 Spring Boot 来提供了 WebServerFactoryCustomizer 这个接口来定制化WebServerFactoryTomcatServletWebServerFactory同时也是实现了WebServerFactory的子接口 ConfigurableWebServerFactory。这个接口是可以对 WebServer 进行配置化,包括 Web 容器的端口。

自定义 WebServerFactoryCustomizer

@Bean
public WebServerFactoryCustomizer customServerPortWebServerFactoryCustomizer() {
    return factory -> {
        if (factory instanceof ConfigurableWebServerFactory) {
            ConfigurableWebServerFactory webServerFactory = ConfigurableWebServerFactory.class.cast(factory);
            webServerFactory.setPort(8888);
        }
    };
}

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

在这里插入图片描述

4、自定义 BeanPostProcessor

其实自定义 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;
        }
    };
}

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

在这里插入图片描述

5、指定传入请求参数

在 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

6、指定传入系统参数

在 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 端口的几种方式。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐