springmvc注解版启动分析

注解版SpringMVC启动分析(一)

​ 使用SpringBoot和SpringCloud全家桶时间长了以后,对最原始的SpringMVC+Tomcat的启动忘记入口?

Question

  1. DispatchServlet如何注册的?
  2. IOC容易如何刷新的?
  3. 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);
	}

总结

posted @ 2021-11-25 22:31  AugustFire  阅读(208)  评论(0)    收藏  举报