SpringBoot server.port配置原理详解
作者:fenglllle
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 { /** * 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。
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启动生效
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。