上一篇文章分析到spring ioc容器的启动,先来回顾一下:
/**
* spring ioc 容器 生命周期
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
在之前通过阅读spring ioc 源码的时候,大家应该都有看到过onRefresh()方法,这是一个空方法有待于spring 其他组件去重写。springboot就重写了此方法,用来做web容器的启动。
一、onRefresh
ServletWebServerApplicationContext#onRefresh
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
//获取servlet容器
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
//创建web容器
ServletWebServerFactory factory = this.getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
createWebServer.end();
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
this.initPropertySources();
}
二、ServletWebServerFactory
上文提到过,在run方法执行的时候,会加载mate-inf/spring.factory中的配置,其中,在spring-boot-autoconfigure-2.3.1.RELEASE.jar包下的spring.factories配置文件中,有一个自动配置类是用于Servlet容器的自动配置的。
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,
看下源码
@Configuration(
proxyBeanMethods = false
)
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
//当前应用是 Servlet Web时才生效,对React不生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
// 1.ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar 可以注册后置处理器哦
// 2.EmbeddedTomcat/EmbeddedJetty/EmbeddedUndertow 配置用于区分创建omcat/Jetty/Undertow这三种不同servlet容器
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
public ServletWebServerFactoryAutoConfiguration() {
}
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties, ObjectProvider<WebListenerRegistrar> webListenerRegistrars) {
return new ServletWebServerFactoryCustomizer(serverProperties, (List)webListenerRegistrars.orderedStream().collect(Collectors.toList()));
}
@Bean
// 仅在类 org.apache.catalina.startup.Tomcat 存在时生效
@ConditionalOnClass(
name = {"org.apache.catalina.startup.Tomcat"}
)
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class})
@ConditionalOnProperty(
value = {"server.forward-headers-strategy"},
havingValue = "framework"
)
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean(filter, new ServletRegistrationBean[0]);
registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ASYNC, DispatcherType.ERROR});
registration.setOrder(-2147483648);
return registration;
}
/**
* 它会向容器注入两个 BeanPostProcessor :
* 1. WebServerFactoryCustomizerBeanPostProcessor
* 作用是在 WebServerFactory 初始化时调用上面自动配置类注入的那些 WebServerFactoryCustomizer,
* 然后调用 WebServerFactoryCustomizer 中的 customize 方法来 处理 WebServerFactory。
* 2. ErrorPageRegistrarBeanPostProcessor
* 和上面的作用差不多,不过这个是处理 ErrorPageRegistrar 的。
*/
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
public BeanPostProcessorsRegistrar() {
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory)beanFactory;
}
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (this.beanFactory != null) {
this.registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class, WebServerFactoryCustomizerBeanPostProcessor::new);
this.registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
}
}
private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<T> beanClass, Supplier<T> instanceSupplier) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
为什么要看这个配置类呢,因为在调用getWebServerFactory这个方法的时候创建了一个WebServerFactory工厂,在bean实例化后会调用对
应的beanPostProcessor。getWebServerFactory源码:
protected ServletWebServerFactory getWebServerFactory() {
String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
} else if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
} else {
//会调用BeanPostProcessor
return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
}
上述代码执行后会走入webServerFactoryCustomizerBeanPostProcessor,看代码:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//创建ServletWebServerFactory后走入此逻辑
if (bean instanceof WebServerFactory) {
this.postProcessBeforeInitialization((WebServerFactory)bean);
}
return bean;
}
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
// 遍历WebServerFactory 中所有 WebServerFactoryCustomizer 类,执行对应的customize方法,去创建Servlet容器
//典型的容器有
//TomcatWebSocketServletWebServerCustomizer
//ServletWebServerFactoryCustomizer
//TomcatServletWebServerFactoryCustomizer
//TomcatWebServerFactoryCustomizer
//这里的处理其实就是去处理配置,初始化tomcat的一些配置绑定到格子的工厂类当中去,就不做分析了
((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
customizer.customize(webServerFactory);
});
}
三、web容器的启动:webServer
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
private ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
// 1. 判断 ServletContext 里面是否存在 WebApplicationContext.class.getName() + ".ROOT"
// 2. 如果不存在则往 ServletContext 里面注册一个根容器,AnnotationConfigServletWebServerApplicationContext
this.prepareWebApplicationContext(servletContext);
// 设置application作用域
this.registerApplicationScope(servletContext);
//将servletContxt放入当前容器中
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
Iterator var2 = this.getServletContextInitializerBeans().iterator();
// 从容器中获取类型为ServletContextInitializer组件并执行他们的onStartup方法
while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
beans.onStartup(servletContext);
}
}
在调用geiWebServer的时候可以看到有三种容器可以选择,我们看下tomcat容器的getWebServer方法:
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
//创建tomcat实例
Tomcat tomcat = new Tomcat();
//创建tomcat工作目录
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
//准备tomcat运行的上下文信息 如webContextPath,容器名称jsp等
this.prepareContext(tomcat.getHost(), initializers);
return this.getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
this.monitor = new Object();
this.serviceConnectors = new HashMap();
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
this.initialize();
}
/**
*最终的容器创建
*/
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
synchronized(this.monitor) {
try {
this.addInstanceIdToEngineName();
Context context = this.findContext();
// 给 Context 对象实例生命周期监听器
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && "start".equals(event.getType())) {
this.removeServiceConnectors();
}
});
//启动tomcat 服务
this.tomcat.start();
this.rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
} catch (NamingException var5) {
}
this.startDaemonAwaitThread();
} catch (Exception var6) {
this.stopSilently();
this.destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", var6);
}
}
}
至此,springboot 中的tomcat启动就结束了。主要就是讲述了下主线的流程,还有一些支线的流程还是需要详细去了解下。