当我加入了spring-boot-starter-actuator依赖,启用actuator之后,在application.properties中配置
management.port=22223
这样spring boot就自动创建了一个tomcat,并将其connector绑定到了此端口上
于是我们可以看到一个springboot应用创建了两个嵌入式tomcat容器
这一行配置是如何生效的呢?
源码分析:
第1步:
我们知道非management.port的嵌入式tomcat,其是在
org.springframework.context.support.AbstractApplicationContext#onRefresh
中进行Initialize的
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
而management.port的嵌入式tomcat,是在onRefresh()方法的下面的方法finishBeanFactoryInitialization中进行初始化的
第2步:
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
完成此上下文的bean factory的初始化,初始化所有剩余的单例bean。
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
smartSingleton.afterSingletonsInstantiated();
第3步:
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration#afterSingletonsInstantiated
@Override
public void afterSingletonsInstantiated() {
ManagementServerPort managementPort = ManagementServerPort.DIFFERENT;
if (managementPort == ManagementServerPort.DIFFERENT) {
if (this.applicationContext instanceof EmbeddedWebApplicationContext
&& ((EmbeddedWebApplicationContext) this.applicationContext)
.getEmbeddedServletContainer() != null) {
createChildManagementContext();
}
}
这里的
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration.ManagementServerPort
这个枚举,提供了get方法,也就是在这里解析management.port配置项
Integer managementPort = getPortProperty(environment, "management.");
if (managementPort == null && hasCustomBeanDefinition(beanFactory,
ManagementServerProperties.class,
ManagementServerPropertiesAutoConfiguration.class)) {
managementPort = getTemporaryBean(beanFactory,
ManagementServerProperties.class).getPort();
}
并且看到,serverPort与managementPort均可以设置。如果不配置management.port,但是引入了spring-boot-actuator,那么就serverPort与managementPort共用一个端口,不过这样对于权限控制起来就比较麻烦
第4步:
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration#createChildManagementContext
private void createChildManagementContext() {
AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
childContext.refresh();
其创建了一个childContext
这里需要开辟第二条线,就是springboot的自动装配autoconfiguration
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration是一个自动装配的类
@Configuration
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@ConditionalOnWebApplication
@AutoConfigureAfter({ PropertyPlaceholderAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
RepositoryRestMvcAutoConfiguration.class, HypermediaAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class })
public class EndpointWebMvcAutoConfiguration
implements ApplicationContextAware, BeanFactoryAware, SmartInitializingSingleton {
其由spring-boot-actuator.jar引入,并自动装配起来
第5步:
回到第4步的childContext.refresh(),之后就回到了正常创建嵌入式web容器的过程了
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#refresh
后面不再赘述,参考:spring boot中嵌入式容器是如何初始化及启动的