我想自定义spring boot嵌入式容器的某些属性,比如启动端口,有下面两种方法
方法1:直接在application.properties中进行配置
server.port=9090
方法2:通过代码硬编码的方式进行配置
代码参考:https://gitee.com/constfafa/spring_springboot_learning/tree/master/springboot-embedded-tomcat
@Configuration
public class TomcatConfiguration implements EmbeddedServletContainerCustomizer {
要使用org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer
来进行自定义,其javadoc如下:
[javadoc]
Strategy interface for customizing auto-configured embedded servlet containers. Any beans of this type will get a callback with the container factory before the container itself is started, so you can set the port, address, error pages etc.
对该接口的调用通常是从EmbeddedServletContainerCustomizerBeanPostProcessor(它是BeanPostProcessor)发出的
It might be safer to lookup dependencies lazily in the enclosing BeanFactory rather than injecting them with @Autowired.
其在哪里使用呢?直接ctrl+g
find EmbeddedServletContainerCustomizer usage
可以看到其是在org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor
中使用的,在嵌入式容器初始化之前,就把容器需要的context等准备好
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
这里需要一个关于org.springframework.beans.factory.config.BeanPostProcessor
的前置知识
[javadoc]
Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.
factory hook 允许自定义修改新的bean实例,例如检查标记接口marking interface或使用代理包装bean。
ApplicationContexts可以在它们的bean定义中自动检测BeanPostProcessor bean,并将它们应用于随后创建的任何bean。
Typically, post-processors that populate beans via marker interfaces or the like will implement postProcessBeforeInitialization, while post-processors that wrap beans with proxies will normally implement postProcessAfterInitialization.
通常,通过标记接口marking interface等填充 populate bean的post-processor将实现postProcessBeforeInitialization,而使用代理proxies包装wrapper bean的后处理器通常将实现postProcessAfterInitialization。
bean的生命周期
而EmbeddedServletContainerCustomizerBeanPostProcessor
是在下面的类中自动装配的
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
EmbeddedServletContainerCustomizerBeanPostProcessor.class, true,false))) {
registry.registerBeanDefinition(
"embeddedServletContainerCustomizerBeanPostProcessor",
new RootBeanDefinition(
EmbeddedServletContainerCustomizerBeanPostProcessor.class));
}
}
}
那么EmbeddedServletContainerAutoConfiguration是如何自动装配的呢?
在spring-boot-autoconfigure包下的META-INF/spring.factories中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
......
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
总结来说:
- spring boot启动时,执行refreshContext方法,其中会执行注册BeanPostProcessor操作
- 在注册BeanPostProcessor过程中,会自动装配 自动装配bean 的引导类,我们这里就是装配了EmbeddedServletContainerAutoConfiguration
- 在EmbeddedServletContainerAutoConfiguration中装配
EmbeddedServletContainerCustomizerBeanPostProcessor
- 装配好之后,当spring boot初始化嵌入式容器的
containerFactory
的时候,就会执行org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor#postProcessBeforeInitialization方法,执行我们的硬编码代码