首页 > 编程语言 > 解决springboot application.properties server.port配置问题
2022
03-17

解决springboot application.properties server.port配置问题

springboot application.properties server.port配置的问题

近年来,springboot以其快速构建方便便捷,开箱即用,约定优于配置(Convention Over Configuration)的特性深受广大开发者喜爱。

springboot已经集成配置好了一套web开发的默认配置,开发者可以无需修改任何配置即可开始一个web工程,但是实际情况中有时候开发者还是需要修改部分默认配置项来使其更加契合自己的项目需求。

下面就其中一个小问题做个记录

在配置服务启动的端口时,springboot默认在application.properties配置文件中提供了server.port配置项来

让开发者自行配置服务启动端口号,**但是注意:**

#服务启动端口号
server.port=8889

该配置项要想生效其实是依赖于项目中内嵌的tomcat容器,如下图:

内嵌tomcat的jar包依赖包含在pom中

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

如果pom中不引人上述依赖,那么项目中不会导入内嵌tomcat的jar包,相应的application.properties配置文件中server.port配置项也将无法生效,因为该配置项实际上修改的就是内嵌tomcat的web端口号。

Spring Boot server.port配置原理

我们经常配置server.port=xxx,但其实这是一个比较复杂的过程才生效的,这次讲讲生效的过程。

1. autoConfigure

本质来源于自动配置

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration

TomcatServletWebServerFactory

为什么是这个类,核心是beanPostProcess原理

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
 
	/**
	 * Server HTTP port.
	 */
	private Integer port;

beanPostProcess

public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
 
	private ListableBeanFactory beanFactory; 
	private List<WebServerFactoryCustomizer<?>> customizers;  
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof WebServerFactory) {
			postProcessBeforeInitialization((WebServerFactory) bean);
		}
		return bean;
	} 
	
	@SuppressWarnings("unchecked")
	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}
 
    private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
		if (this.customizers == null) {
			// Look up does not include the parent context
			this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
			this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}
 
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
		return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
	}

最终

beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values()

WebServerFactoryCustomizer对象.customize(webServerFactory)

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
 
	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}

这里就将port设置好了。

这里使用函数式编程,lambda表达式,将port的值设置进了

ConfigurableServletWebServerFactory ,即TomcatServletWebServerFactory对象

2. embed tomcat如何使用

tomcat创建时,会通过getBean方式获取工厂

就是 TomcatServletWebServerFactory

然后设置connector,从TomcatServletWebServerFactory读取port,设置connector,设置结束

总结

Spring Boot在解耦的时候绕了很多弯,先@Bean factory对象,然后BeanPostProcess,然后启动embed tomcat 在factory 中new Tomcat 然后设置Connector,设置port。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持自学编程网。

编程技巧