这里的SpringMvc是基于注解版的, 在Servlet3.0之后注解版为主要的实现方式。
public class AppStarter implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Ioc 容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMVCConfig.class);
// IOC未启动
// 配置DispatchServlet: FrameworkServlet: initServletBean()
DispatcherServlet servlet = new DispatcherServlet(context);
// servlet加入到servletContext后,Tomcat会对DispatcherServlet初始化
ServletRegistration.Dynamic registration = servletContext.addServlet("servlet", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
文章目录
1.Spi机制处理
Servlet的规范ServletContainerInitializer的实现类SpringServletContainerInitializer
上面的注解@HandlesTypes
代表着WebApplicationInitializer
这个接口的实现都是来自Spi机制的。
于是加载了所有实现WebApplicationInitializer的接口的类
2.调用onStarterup方法
于是找到了AppStarter这个主类, 调用WebApplicationInitializer的onStartup方法。
这个方法:
- 实例化一个ioc容器, 但是只是一个空的容器
- 实例化DispatcherServlet, 并在其中传入ioc容器, 并注册到了ServletContext中, 就是注册到了Tomcat中
这里因为DipatcherServlet是一个Servlet, 所以会遵循Servlet规范:
- Servlet 创建对象
- Servlet 调用init初始化
- 每次请求调用service方法进行处理
- tomcat停止的时候调用destroy方法
3.DispatcherServlet类分析
根据DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> GenericServlet -> Servlet
这里的HttpServlet -> GenericServlet -> Servlet 为Servlet包下的
DispatcherServlet -> FrameworkServlet -> HttpServletBean 是Spring包下的
Servlet.service()
-> GenericService.service()
-> HttpServlet.service():doGet/Post
-> HttpServletBean
-> FrameworkServlet.processRequest(): 统一处理请求的入口
-> DispatcherServlet.doService()
下一篇进行介绍
HttpServletBean 会有一个强大的init方法:
这里的initServletBean为模板方法模式, 为子类提供扩展
FrameworkServlet#initServletBean()
initFrameworkServlet为模板方法模式, 为子类提供扩展
4.web容器的准备阶段
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
这个方法中提供了父子容器
的概念。
这个方法中有onRefresh
方法, 是spring提供的一个模板方法的扩展方法
这个onRefresh()方法提供了根据不同的策略来初始化容器中的组件
这里设计到了web容器的9大组件。下一篇进行介绍。
5.Question
1.ioc容器是什么时候初始化的
RA:
1.Tomcat启动的时候, 会创建每一个Servlet对象
2.Tomcat会给每一个DispatcherServlet创建对象
3.当DispatcherServlet初始化之后 ioc容器也会初始化
2.9大组件什么时候初始化的
RA:
利用的是Spring的事件驱动初始化的。
1.tomcat启动
2.触发DS初始化
3.初始化全部结束后, 容器会发送事件, 初始化9大组件
3.IOC容器和web容器是什么时候初始化的
RA:
IOC容器为tomcat启动后, 监听器钩子启动IOC容器, 实例化: 应用启动监听器回调。
web容器为tomcat调用DS的初始化init(), 进行初始化: DS初始化init()回调。