SpringMVC初始化階段流程源碼分析
阿新 • • 發佈:2019-03-01
ext and 啟動 rtti nal apm isa 分析 img
1、都知道SpringMVC項目啟動的時候都會初始化一個類:DispatcherServlet,看這個類的源碼我們可以發現他其實就是一個servlet,
為什麽這麽說呢?請看:
DispatcherServlet extends FrameworkServlet
FrameworkServlet extends HttpServletBean
HttpServletBean extends HttpServlet
初始化這個DispatcherServlet的時候我們可以看到這個類裏面有一個靜態代碼塊:根據代碼可以看出代碼塊裏面會去讀取DispatcherServlet.properties配置文件裏面的配置,load到Properties集合裏面
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final Properties defaultStrategies;
static { try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies= PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load ‘" + DEFAULT_STRATEGIES_PATH + "‘: " + ex.getMessage()); } }
2、我們都知道一個servlet初始化階段 ,會調用init()方法,那麽這邊會先調用HttpServlet的子類HttpServletBean裏面的init方法:org.springframework.web.servlet.HttpServletBean#init,這個方法裏面調用了initServletBean這個方法:org.springframework.web.servlet.FrameworkServlet#initServletBean
@Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet ‘" + getServletName() + "‘"); } // 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; } } // Let subclasses do whatever initialization they like. initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet ‘" + getServletName() + "‘ configured successfully"); } }
org.springframework.web.servlet.FrameworkServlet#initServletBean裏面調用了org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
@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 | 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"); } }
org.springframework.web.servlet.FrameworkServlet#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方法:裏面做了一些列的初始化操作,具體哪個方法對應什麽功能呢?請大家自行看裏面的源碼,我這邊主要說的是
initHandlerMappings(context);
initHandlerAdapters(context);
這兩個方法就是初始化我們的映射器和我們的適配器的,到此我們的初始化就結束了;
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { //此方法主要做文件上傳處理的 initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //此方法主要是獲取配置文件DispatcherServlet.properties裏面的handlerMapping類型對象 initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
SpringMVC初始化階段流程源碼分析