springmvc注解版启动分析
注解版SpringMVC启动分析(一)
使用SpringBoot和SpringCloud全家桶时间长了以后,对最原始的SpringMVC+Tomcat的启动忘记入口?
Question
- DispatchServlet如何注册的?
- IOC容易如何刷新的?
- SpringMVC如何初始化的?
废话不多说,直接开干!
一.搭建mvc,Servlet3.0环境
1.项目结构

2.项目依赖

3.主要代码
MyWebAppInitializer
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{AppConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
AppConfig
@Configuration
@EnableWebMvc
@ComponentScan("com.young.controller")
public class AppConfig extends WebMvcConfigurerAdapter {
//配置视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认前缀 /WEB-INF/ 后缀.jsp
registry.jsp();
}
}
RootConfig
@Configuration
@ComponentScan("com.young.service")
public class RootConfig {
}
二.启动分析
根据之前的Servlet分析 ,Tomcat启动会调用感兴趣的类WebApplicationInitializer及其子实现类的onStartup()方法
查看MyWebAppInitializer的继承uml

根据继承特性,从下层往上次找onStartup
在org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup中
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext); //查看此处代码
registerDispatcherServlet(servletContext);
}
org.springframework.web.context.AbstractContextLoaderInitializer#onStartup
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext); //查看此处代码
}
protected void registerContextLoaderListener(ServletContext servletContext) {
// 创建父容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
// 给父容器添加监听器!!!非常重要
// ContextLoaderListener会在Servlet容器启动后发布收到相关事件到`contextInitialized`
// @See org.springframework.web.context.ContextLoaderListener.contextInitialized
// 初始化父容器
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
// 添加到servletContext
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
registerDispatcherServlet注册DispatchServlet
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
// 创建Servlet子容器
WebApplicationContext servletAppContext = createServletApplicationContext();
// 创建dispatcherServlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
// 将dispatcherServlet添加到servletContext中
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
// Servlet容器一启动就加载
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
// 定制servlet
customizeRegistration(registration);
}
三.DispatcherServlet

tomcat加载Servelet后,会调用Servlet的init方法,老规矩,从下而上找init()
org.springframework.web.servlet.HttpServletBean#initServletBean
org.springframework.web.servlet.FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
this.webApplicationContext = initWebApplicationContext();
}
}
org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
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()) {
if (cwac.getParent() == null) {
// 设置子容器的父容器
cwac.setParent(rootContext);
}
// 配置并刷新子容器
configureAndRefreshWebApplicationContext(cwac);
}
}
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) {
// 重要!!!initStrategies 监听调用!
onRefresh(wac);
}
}
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();// 刷新子容器
}
初始化SpringMVC组件
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //文件上传解析
initLocaleResolver(context); //本地语言解析
initThemeResolver(context); //主题解析
initHandlerMappings(context); //url请求映射器
initHandlerAdapters(context); //处理器适配器
initHandlerExceptionResolvers(context); //异常解析iq
initRequestToViewNameTranslator(context);
initViewResolvers(context); //视图解析器
initFlashMapManager(context);
}
总结

本文来自博客园,作者:AugustFire,转载请注明原文链接:https://www.cnblogs.com/august-fire/p/15605379.html

浙公网安备 33010602011771号