web.xml中的ContextLoaderListener和DispatcherServlet区别

ContextLoaderListener和DispatcherServlet都会在Web容器启动的时候加载一下bean配置. 区别在于:

  DispatcherServlet一般会加载MVC相关的bean配置管理(如: ViewResolver, Controller, MultipartResolver, ExceptionHandler, etc.)

  ContextLoaderListener一般会加载整个Spring容器相关的bean配置管理(如: Log, Service, Dao, PropertiesLoader, DataSource Bean, etc.)

ContextLoaderListener继承ContextLoader类,实现ServletContextListener接口(该接口监听servlet容器的启动和销毁),ContextLoaderListener重写了监听容器启动和销毁的方法,在启动时(contextInitialized),会调用initWebApplicationContext方法,进行web容器初始化。

	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}


	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}

在initWebApplicationContext方法时父类contextloader内的方法(精简):

在方法内回调用createWebApplicationContext()创建容器,该容器回根据spring内部的配置文件创建,最后强制为ConfigurableWebApplicationContext对象

	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}
		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);//ConfigurableWebApplicationContext类型对象
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {//进行初始化操作
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				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 ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);//真正初始化,在该方法内部有refresh()方法,在方法回调用ConfigurableWebApplicationContext父类的refresh()方法进行容器初始化
                                                            //也就是AbstractApplicationContext类中的refresh()方法 } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); return this.context; } }
    protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        Class<?> contextClass = determineContextClass(sc);
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
                    "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
        }
        return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    }
    protected Class<?> determineContextClass(ServletContext servletContext) {
        String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
        if (contextClassName != null) {
            try {
                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
            }
            catch (ClassNotFoundException ex) {
                throw new ApplicationContextException(
                        "Failed to load custom context class [" + contextClassName + "]", ex);
            }
        }
        else {
            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
            try {//通过反射得到一个class对象
                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
            }
            catch (ClassNotFoundException ex) {
                throw new ApplicationContextException(
                        "Failed to load default context class [" + contextClassName + "]", ex);
            }
        }
    }

 DispatcherServlet本质是一个servlet,能够拦截请求

servlet会有初始化init,同dispatcherservlet,会进行一些初始化操作:

    protected void initStrategies(ApplicationContext context) {

      //初始化多部请求解析器,没有默认的实现
      initMultipartResolver(context); //文件上传
      //初始化地域解析器,默认实现是AcceptHeaderLocaleResolver
      initLocaleResolver(context);
      //初始化主题解析器,默认实现是FixedThemeResolver
      initThemeResolver(context);
      //初始化处理器映射,这是个集合, 默认实现是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping
      initHandlerMappings(context);
      //初始化处理器适配器,这是个集合,默认实现是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter
      initHandlerAdapters(context);
      //初始化处理器异常解析器,这是个集合,默认实现是AnnotationMethodHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
      initHandlerExceptionResolvers(context);
      //初始化请求到视图名解析器,默认实现是DefaultRequestToViewNameTranslator
      initRequestToViewNameTranslator(context);
      //初始化视图解析器,这是个集合,默认实现是InternalResourceViewResolver
      initViewResolvers(context);   

}

原文地址:https://www.cnblogs.com/nxzblogs/p/9139687.html