6.Spring MVC自身的创建过程

本文详细解析了SpringMVC的初始化过程,包括HttpServletBean、FrameworkServlet和DispatcherServlet三个核心类的创建步骤,并介绍了如何通过它们初始化WebApplicationContext。

前言

       Spring MVC本质是一个Servlet;

       本文将介绍Spring MVC自身的创建过程。首先,先介绍Spring MVC的整体结构,然后具体分析每一层的创建过程;

整体结构介绍


       

       如上图所示,主要是5个类:GenericServlet和HttpServlet在java中;剩下的三个类HttpServletBean,FrameworkServlet和DispatcherServlet是在Spring MVC中的;

       本文主要介绍这三个类的创建过程;
       这三个类直接实现了三个接口:EnvironmentCapable,EnvironmentAware和ApplicationContextAware。
       XXXAware在Spring里表示对XXX的感知,通俗点解释就是:如果在某个类里面想要使用Spring的一些东西,就可以通过实现XXXAware接口告诉Spring,Spring看到后就会给你送过来,而接收的方式是通过实现该接口的唯一方法set-XXX;
       例如,有一个类想要使用当前的ApplicationContext,那么通过让它实现ApplicationContextAware接口,实现接口中的唯一的方法void setApplicationContext(ApplicationContext);Spring就会自动调用这个方法,将ApplicationContext传给这个类。
      EnvironmentCapable:可以提供Environment,它的唯一方法就是Environment getEnvironment();实现了这个接口的类,就是告诉Spring它可以提供Environment;当Spring需要Environment的时候,就会调用它的getEnvironment()来获取;

       当然,这里说的Environment也是通过实现EnvironmentAware接口,Spring传递进来的;

---------------------------------------------------------

     ApplicationContext代表的是整个应用,而Environment和ServletContext有点类似;实际上,HttpServletBean中的Environment使用的是Standard-Servlet-Environment,这里的确封装了ServletContext,同时也封装了ServletConfig,系统环境变量和系统属性等,这些都被封装到了其propertySources属性下;

HttpServletBean

       通过前面对Servelt的分析,我们知道Servlet创建的时候可以直接调用无参数的init方法;HttpServletBean的init方法如下:

        public final void init() throws ServletException {
		// Set bean properties from init parameters.
                // 将Servelt中配置的参数封装到pvs变量中,requiredProperties为必需参数,如果没配置将报异常
		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()));
				//模板方法,可以在子类上调用,做一些初始化工作,bw代表DispatcherServlet
                                initBeanWrapper(bw);
                                //将配置的初始化值(如contextConfigLocation)设置到DispatcherServlet
				bw.setPropertyValues(pvs, true);
			}
			.........
		}

		// Let subclasses do whatever initialization they like.
                //模板方法,子类初始化的入口方法
		initServletBean();
                .......
	}

      在init方法中,首先将Servlet中配置的参数使用BeanWrapper设置到DispatcherServlet的相关属性,然后调用模板方法initServletBean,子类就通过这个方法初始化;

什么是BeanWrapper

       BeanWrapper是Spring提供的一个用来操作JavaBean属性的工具,使用它可以直接修改一个对象的属性;

FrameworkServlet

       从HttpServletBean中可知,FrameworkServlet的初始化入口方法应该是initServletBean();

         protected final void initServletBean() throws ServletException {
		......
		try {
                        //下面两句才是核心代码
                        //初始化WebApplicationContext和FrameworkServlet
			this.webApplicationContext = initWebApplicationContext();
                        //initFramework是模板方法,子类可以覆盖然后在里面做一些初始化工作,但子类没有使用它
                        //可见,FrameworkServlet的主要作用是初始化WebApplicationContext
			initFrameworkServlet();
		}
		......
	}
        protected WebApplicationContext initWebApplicationContext() {
                //获取Spring的根容器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(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
                        //当webApplicationContext已经存在ServletContext中时,通过配置在Servlet中的contextAttribute参数获取
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
                        //如果webApplicationContext还没创建,那就创建一个
			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.
                        //当ContextRefreshedEvent事件没有触发时调用此方法,模板方法,可以在子类中重写
			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;
	}

DispatcherServlet

          onRefresh()是DispatcherServlet的入口方法;onRefresh()中简单地调用了initStrategies();

        @Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * 初始化9个组件
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值