应用上下文ApplicationContext
环境准备完毕后是打印Banner,然后创建上下文。因为是Servlet环境,这里返回AnnotationConfigServletWebServerApplicationContext,它就是应用上下文,其中有个成员变量beanFactory是DefaultListableBeanFactory的对象引用,它是默认的IoC容器。
SpringApplication->run():
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
SpringApplication->prepareContext():
// 遍历initializers,执行应用上下文初始化类的initialize方法
applyInitializers(context);
// 触发监听器调用应用上下文初始化完毕(ApplicationContextInitializedEvent)事件
listeners.contextPrepared(context);
// 打印启动信息及配置文件信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
......
// 将构造方法参数(primarySources成员变量)解析,如果是bean的话添加至bdn和bdm,有多个则按照顺序添加
load(context, sources.toArray(new Object[0]));
// 先将SpringBoot中的监听器赋给应用上下文,触发监听器调用应用准备完毕(ApplicationPreparedEvent)事件
listeners.contextLoaded(context);
Tomcat的实例化
AbstractApplicationContext->refresh():
// 初始化容器中的特殊bean
onRefresh();
ServletWebServerApplicationContext->onRefresh():
// 创建tomcat容器
createWebServer();
ServletWebServerApplicationContext->createWebServer():
// 第一次进来webServer和servletContext都为空,所以走第一个if方法
ServletWebServerFactory factory = getWebServerFactory();
// this指的是AnnotationConfigServletWebServerApplicationContext
this.webServer = factory.getWebServer(getSelfInitializer());
initPropertySources();
getWebServerFactory()注入ServletWebServerFactory子类对象,由ServletWebServerFactoryAutoConfiguration类引入,最终实例化TomcatServletWebServerFactory对象,可以看到该类下除了Tomcat还有Jetty和Undertow,之所以没有添加到容器,是@ConditionalOnClass和@ConditionalOnMissingBean这两个注解起到了作用。
// 终于在这里看到了Tomcat的踪迹
TomcatServletWebServerFactory->getWebServer():
// 初始化Tomcat对象
Tomcat tomcat = new Tomcat();
// 设置tomcat目录
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 实例化connector组件,内部实例化Http11NioProtocol,Http11NioProtocol内部实例化Endpoint
Connector connector = new Connector(this.protocol);
// 实例化server以及service组件,之后server添加service,service添加connector
tomcat.getService().addConnector(connector);
// 自定义的属性值,如端口号
customizeConnector(connector);
tomcat.setConnector(connector);
// 实例化engine组件,service添加engine,实例化host组件,之后engine添加host
tomcat.getHost().setAutoDeploy(false);
......
// 实例化context组件,之后实例化wrapper组件,之后context添加wrapper,host添加context
// 至此,Tomcat四大组件完成
prepareContext(tomcat.getHost(), initializers);
// 启动tomcat服务
return getTomcatWebServer(tomcat);
用户配置文件中server开头的属性会被注入到ServerProperties类成员变量,它用于自定义Tomcat的属性值。
Tomcat的结构如图所示,其中server是Tomcat类的一个成员变量属性。host、context、wrapper是各组件的children成员变量。
Tomcat的启动
每个组件都是抽象类ContainerBase的子类,ContainerBase又是抽象类LifecycleMBeanBase的子类,LifecycleMBeanBase又是LifecycleBase的子类。
LifecycleBase->start():如果生命周期状态是NEW,调用init()方法,生命周期状态置为STARTING_PREP,调用startInternal()方法,生命周期状态置为STARTED(没出错的情况下)
LifecycleMBeanBase->initInternal():注册当前对象到JMX
ContainerBase->initInternal():注册一个startStop线程池
ContainerBase->startInternal():将子容器的启动放入startStop线程池中,等待其完成之后,启动背景线程。
LifecycleBase->fireLifecycleEvent():使监听器执行生命周期状态改变的事件
server、service、engine的启动
Tomcat的启动主要是各组件的启动,生命周期的变化贯穿其中。
TomcatWebServer->initialize():
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
......
this.tomcat.start();
Tomcat->start():
server.start();
大致过程如下图所示,每个组件的生命周期独立。这里的组件2是组件1的最后一个组件,组件3是组件2的最后一个组件,以此类推。
-
initInternal中: 在connector的initInternal()中,实例化了CoyoteAdapter -
startInternal中: 从engine开始,子组件采用异步线程的形式启动。
service调用mapperListener.start(),初始化路由映射器Mapper类的相关属性。
service遍历connectors对象,会发现两者已经解绑了。
host、context、wrapper的启动
由于engine对应多个host,host对应多个context,所以它们的子组件采用异步线程的形式启动。
ContainerBase->startInternal():
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
// StartChild实现Callable接口
StartChild ->call():
child.start();
startInternal中: context调用child.start(),wrapper的启动又用回了同步的形式。
在context的startInternal()中,实例化了StandardManager
context的setManager(contextManager),选择了一种sessionId的生成方式
context的onStartup(entry.getValue(),getServletContext()),遍历其成员变量initializers执行onStartup()方法 // --1
context调用super.threadStart()启动背景线程,背景线程执行backgroundProcess()方法,判断session是否过期。
context的setState(LifecycleState.STARTING),将service和connectors解绑,关于解绑的代码和后续可以点击此处
servlet、filter的查找与添加
// --1 最终进入以下方法
ServletWebServerApplicationContext->selfInitialize():
// 作用域新增application
registerApplicationScope(servletContext);
// getServletContextInitializerBeans()返回框架以及用户自定义的servlet和filter子类
// context添加servlet和filter
// 如果是servlet,在children中体现,仍会调用child.start()启动wrapper
// 如果是filter,在filterDefs与filterMaps中体现
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
ServletWebServerApplicationContext->getServletContextInitializerBeans():
return new ServletContextInitializerBeans(getBeanFactory());
ServletContextInitializerBeans->ServletContextInitializerBeans():
this.initializerTypes = Collections.singletonList(ServletContextInitializer.class);
// 从IoC容器中找到实现ServletContextInitializer接口的类,将它们的泛型归类,一个是Servlet的实现类,一个是Filter的实现类
addServletContextInitializerBeans(beanFactory);
addAdaptableBeans(beanFactory);
// 按照从小到大的顺序排序,如果是Ordered接口子类,取其getOrder()方法,否则取@Order或@Priority属性值,否则默认整型最大值
List<ServletContextInitializer> sortedInitializers = this.initializers.values()
.stream()
.flatMap((value) -> value.stream()
.sorted(AnnotationAwareOrderComparator.INSTANCE))
.collect(Collectors.toList());
ServletContextInitializerBeans->addAdaptableBeans():
// 添加IoC容器中实现Servlet接口的类
addAsRegistrationBean(beanFactory, Servlet.class,
new ServletRegistrationBeanAdapter(multipartConfig));
// 添加IoC容器中实现Filter接口的类
addAsRegistrationBean(beanFactory, Filter.class,
new FilterRegistrationBeanAdapter());
context启动完毕,层层回溯,最终,Tomcat启动完毕。
因为没有启动connector,所以此时是不能接收请求的,关于Tomcat接收请求的时机和代码请此处