Spring MVC初始化过程源码分析

1. 引言

Spring MVC核心结构图如下所示
DispatcherServlet结构图
其中aware意为感知,实现XXXAware接口就会通过接口的唯一方法setXXX得到ApplicationContext或Environment等。EnvironmentCapable有惟一方法getEnvironment()。同时需要注意的是ApplicationContext为应用上下文,Environment封装了servletContext、servletConfig、JndiProperty、系统环境变量和系统属性等。

2. HttpServletBean

HttpServlet的简单扩展,它将配置参数(web.xml中servlet标记中的init-param条目)视为bean属性。
对于任何类型的servlet都是一个方便的超类。他实现了EnvironmentAware和EnvironmentCapable可以获取environment属性。这里主要关注其init()方法。

/**
	 * Map config parameters onto bean properties of this servlet, and
	 * invoke subclass initialization.
	 * @throws ServletException if bean properties are invalid (or required
	 * properties are missing), or if subclass initialization fails.
	 */
	@Override
	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);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		// 由子类实现初始化
		initServletBean();
	}

可以看到子类通过重写initServletBean()方法来进一步初始化。

3. FrameworkServlet

/**
	 * Overridden method of {@link HttpServletBean}, invoked after any bean properties
	 * have been set. Creates this servlet's WebApplicationContext.
	 */
	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			//初始化WebApplicationContext
			this.webApplicationContext = initWebApplicationContext();
			//空方法,子类可以重写
			initFrameworkServlet();
		}
		catch (ServletException ex) {
			...

在FrameworkServlet中重写了initServletBean()方法,其主要做了两件事

//初始化webApplicationContext
this.webApplicationContext = initWebApplicationContext();
//初始化FrameworkServlet,模板方法
initFrameworkServlet();

让我们来了解一下initWebApplicationContext方法

	/**
	 * Initialize and publish the WebApplicationContext for this servlet.
	 * <p>Delegates to {@link #createWebApplicationContext} for actual creation
	 * of the context. Can be overridden in subclasses.
	 */
	protected WebApplicationContext initWebApplicationContext() {
		//获取rootContext
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
		//如果已经通过构造方法设置了WebApplicationContext
		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方法用于封装ApplicationContext数据并且初始化所有相关Bean对象。
					//它会从web.xml中读取名为contextConfigLocation的配置,这就是spring xml数据源设置,然后放到ApplicationContext中,
					//最后调用传说中的refresh方法执行所有Java对象的创建
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			//从servlet context中获取webApplicationContext
			// 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) {
			//如果从servlet context中找不到就创建一个新的
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			//如果没有refresh,在这里刷新
			// 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.
			onRefresh(wac);
		}

		if (this.publishContext) {
			//将ApplicationContext保存到ServletContext中
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

initWebApplicationContext方法做了三件事:

  1. 获取spring的根容器rootContext
  2. 设置webApplicationContext并根据情况调用onRefresh方法
  3. 将webApplicationContext设置到ServletContext中

整个FrameworkServlet中重要的事情就是将创建出来的WebApplicationContext设置到ServletContext中,方便获取。

4. DispatcherServlet

onRefresh方法是DispatcherServlet的入口方法,onrefresh调用了initStrategies,在initStrategies中调用了9个初始化方法

	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);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

5. 小结

简单分析了一个Spring MVC的创建过程,Spring MVC中Servlet一共有三个层次,分别是HttpServletBean,FrameworkServlet和DispatcherServlet。HttpServletBean直接继承自Java的HttpServlet,其作用是将Servlet中配置的参数设置到对应的属性;FrameworkServlet初始化了WebApplciationContext,DispatcherServlet初始化了自身的9个组件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值