• SpringMVC DispatcherServlet初始化过程


    先来上一张类的结构图:


    图里仅仅画了跟初始化相关的方法。

    首先DispatcherServlet也是一个Servlet,初始化从init()方法開始。

    以下就详细看看ini()是怎么实现的吧。

    1.Servlet 是个接口;

        public void init(ServletConfig config) throws ServletException;

    2.GenericServlet 中实现了初始化方法。

        public void init(ServletConfig config) throws ServletException {
    	this.config = config;
    	this.init();
        }
    

    这里调用了一个没有參数的init();是个空方法;

    public void init() throws ServletException {
    
        }

    3.HttpServlet 没有对初始化相关的方法进行覆盖。

    4.HttpServletBean。重写了init()方法。

    @Override
    	public final void init() throws ServletException {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Initializing servlet '" + getServletName() + "'");
    		}
    
    		// Set bean properties from init parameters.
    		try {
    			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    			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) {
    			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
    			throw ex;
    		}
    
    		// Let subclasses do whatever initialization they like.
    		initServletBean();
    
    		if (logger.isDebugEnabled()) {
    			logger.debug("Servlet '" + getServletName() + "' configured successfully");
    		}
    	}

    当中又掉了一个initServletBean();方法,这本类中也是个空实现。

    	protected void initServletBean() throws ServletException {
    	}

    5.FrameworkServlet 果不其然的重写了上边留空的方法:initServletBean();

    @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 {
    			this.webApplicationContext = initWebApplicationContext();
    			initFrameworkServlet();
    		}
    		catch (ServletException ex) {
    			this.logger.error("Context initialization failed", ex);
    			throw ex;
    		}
    		catch (RuntimeException ex) {
    			this.logger.error("Context initialization failed", ex);
    			throw ex;
    		}
    
    		if (this.logger.isInfoEnabled()) {
    			long elapsedTime = System.currentTimeMillis() - startTime;
    			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
    					elapsedTime + " ms");
    		}
    	}

    在这种方法中最重要的就是调用了一个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()) {
    					// 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
    			wac = findWebApplicationContext();
    		}
    		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.
    			onRefresh(wac);
    		}
    
    		if (this.publishContext) {
    			// 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;
    	}

    一系列的赋值和推断。最关键的,跟初始化相关的,就是调用了onRefresh(),相同的套路,这种方法在本类中为空实现。留给子类去实现。

    6.最终到了DispatcherServlet,找到onRefresh()。简单!调用initStrategies(ApplicationContext context);这种方法就在下边,这下清楚了,一堆的初始化方法。详细代码就不粘了。

    /**
    	 * This implementation calls {@link #initStrategies}.
    	 */
    	@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);
    		initHandlerMappings(context);
    		initHandlerAdapters(context);
    		initHandlerExceptionResolvers(context);
    		initRequestToViewNameTranslator(context);
    		initViewResolvers(context);
    		initFlashMapManager(context);
    	}

    到这里整个载入过程就理清楚了。

  • 相关阅读:
    第六周作业
    第二次作业
    自我介绍
    2019春总结作业
    2019春第四次课程设计实验报告
    2019春第三次课程设计实验报告
    2019春第二次课程设计实验报告
    2019春第一次课程设计实验报告
    第十二周编程总结
    第十一周编程总结
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6852749.html
Copyright © 2020-2023  润新知