SpringBoot server.port配置原理
我们经常配置server.port=xxx,但其实这是一个比较复杂的过程才生效的,这次讲讲生效的过程。
1. autoConfigure
本质来源于自动配置
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration
TomcatServletWebServerFactory
为什么是这个类,核心是beanPostProcess原理
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
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。
server.port不起作用
启动项目报错:
org.apache.catalina.LifecycleException: Protocol handler start failed
怀疑可能端口号冲突,在 application.properties 添加 server.port=8080 未生效
立刻百度一圈没找到答案(感觉可能自己犯的错误太低级),突然想起可能是环境配置里面的配置给覆盖了
#读取环境配置dev(开发)/pro(生产)/test(测试)
spring.profiles.active=dev
找到 application-dev.properties、application-prod.properties 发现果然存在
按照配置的 dev 找到 application-dev.properties 修改 server.port=8080启动生效
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。