Spring MVC的初始化

倾然丶 夕夏残阳落幕 提交于 2020-02-28 00:57:17

初始化Spring MVC

  1. 项目启动的时候不会对Spring MVC进行初始化,会在接收到第一个请求的时候进行初始化。
  2. 首先到了GenericServlet#init(ServletConfig)中,然后调用this#init()方法,此处的this指向是DispatcherServlet对象
public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}
  1. DispatcherServlet对象执行init()方法,DispatcherServlet对象中的这个方法是继承自HttpServletBean,此时会进入到HttpServletBean#init中,这里面的重点是initServletBean()方法,调用对应的子类进行初始化
public final void init() throws ServletException {
	// Set bean properties from init parameters.
	PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
	if (!pvs.isEmpty()) {
		try {
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			initBeanWrapper(bw);
			bw.setPropertyValues(pvs, true);
		}
		//...忽略
	}
	// Let subclasses do whatever initialization they like. 让子类进行对应的初始化
	initServletBean();
}
  1. 进入到FrameworkServlet#initServletBean中,核心是initWebApplicationContextinitFrameworkServlet方法,initFrameworkServlet()是个空方法。
protected final void initServletBean() throws ServletException {
	getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
	try {
		//
		this.webApplicationContext = initWebApplicationContext();
		//
		initFrameworkServlet();
	}
	catch (ServletException | RuntimeException ex) {
		logger.error("Context initialization failed", ex);
		throw ex;
	}
	//log..
}
  1. 首先进入到了initWebApplicationContext方法,对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);
			}
		}
	}
	//查找web容器的引用是否存在, 并创建好空ioc容器
	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();
	}
	//给建好的IOC容器赋值
	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;
}
  1. IOC容器初始化以后,调用了DispatcherServletonRefresh,在onRefresh中又调用了initStrategies方法,初始化SpringMVC的九大组件
@Override
protected void onRefresh(ApplicationContext context) {
	initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
	//多文件上传组件
	initMultipartResolver(context);
	//本地语言环境
	initLocaleResolver(context);
	//模板处理器
	initThemeResolver(context);
	//HandlerMapping
	initHandlerMappings(context);
	//适配器
	initHandlerAdapters(context);
	//异常拦截器
	initHandlerExceptionResolvers(context);
	//视图预处理器
	initRequestToViewNameTranslator(context);
	//视图转换器
	initViewResolvers(context);
	//FlashMap
	initFlashMapManager(context);
}

附录: 九大组件

  1. HandlerMapping 根据request找到相应的处理器。因为Handler(Controller)有两种形式,一种是基于类的Handler,另一种是基于Method的Handler(也就是我们常用的)

  2. HandlerAdapter 调用Handler的适配器。如果把Handler(Controller)当做工具的话,那么HandlerAdapter就相当于干活的工人

  3. HandlerExceptionResolver 对异常的处理

  4. ViewResolver 用来将String类型的视图名和Locale解析为View类型的视图

  5. RequestToViewNameTranslator 有的Handler(Controller)处理完后没有设置返回类型,比如是void方法,这是就需要从request中获取viewName

  6. LocaleResolver 从request中解析出Locale。Locale表示一个区域,比如zh-cn,对不同的区域的用户,显示不同的结果,这就是i18n(SpringMVC中有具体的拦截器LocaleChangeInterceptor)

  7. ThemeResolver 主题解析,这种类似于我们手机更换主题,不同的UI,css等

  8. MultipartResolver 处理上传请求,将普通的request封装成MultipartHttpServletRequest

  9. FlashMapManager 用于管理FlashMap,FlashMap用于在redirect重定向中传递参数

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!