Spring及SpringMVC初始化源码分析
首先SpringServletContainerInitializer会执行onStartup()方法(SpringServletContainerInitializer是实现ServletContainerInitializer接口且实现了Servlet3.0的@HandlesTypes(WebApplicationInitializer.class))。
执行onStartup时,会把实现WebApplicationInitializer的接口按Set集合传入方法中。方法中会把符合判断的类加入到集合中。如果集合不为空,会执行WebApplicationInitializer.onStartup()方法,这里执行的是WebApplicationInitializer的实现类AbstractDispatcherServletInitializer的onStartup(),AbstractDispatcherServletInitializer中执行父类onStartup()方法。代码如下:
SpringServletContainerInitializer类
[code]public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer) waiClass.newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { //执行AbstractDispatcherServletInitializer的onStartup initializer.onStartup(servletContext); } }
AbstractDispatcherServletInitializer类
[code]public void onStartup(ServletContext servletContext) throws ServletException { //调用父类方法 super.onStartup(servletContext); //初始化SpringMVC容器并封装到FrameworkServlet中。 registerDispatcherServlet(servletContext); } protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = getServletName(); Assert.hasLength(servletName, "getServletName() must not return empty or null"); WebApplicationContext servletAppContext = createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() did not return an application " + "context for servlet [" + servletName + "]"); //封装到WebApplicationContext FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); Assert.notNull(registration, "Failed to register servlet with name '" + servletName + "'." + "Check if there is another servlet registered under the same name."); registration.setLoadOnStartup(1); registration.addMapping(getServletMappings()); registration.setAsyncSupported(isAsyncSupported()); Filter[] filters = getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { registerServletFilter(servletContext, filter); } } customizeRegistration(registration); }
AbstractContextLoaderInitializer类
[code]public void onStartup(ServletContext servletContext) throws ServletException { //初始化Spring容器 registerContextLoaderListener(servletContext); }
在AbstractContextLoaderInitializer中,方法registerContextLoaderListener(ServletContext servletContext)会创建Spring的容器WebApplicationContext并封装到ContextLoader中。然后在ServletContext中注册监听器ContextLoaderListener。
AbstractContextLoaderInitializer类
[code]protected void registerContextLoaderListener(ServletContext servletContext) { //初始化Spring的容器 WebApplicationContext rootAppContext = createRootApplicationContext(); if (rootAppContext != null) { //把Spring的容器封装到ContextLoader中。 ContextLoaderListener listener = new ContextLoaderListener(rootAppContext); listener.setContextInitializers(getRootApplicationContextInitializers()); 在ServletContext中注册ContextLoaderListener监听器 servletContext.addListener(listener); } else { logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not return an application context"); } }
然后继续执行AbstractDispatcherServletInitializer中的registerDispatcherServlet(ServletContext servletContext)方法。代码如下:
AbstractDispatcherServletInitializer类
[code]public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); //初始化SpringMVC容器并封装到FrameworkServlet中。 registerDispatcherServlet(servletContext); } protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = getServletName(); Assert.hasLength(servletName, "getServletName() must not return empty or null"); //初始化SpringMVC容器并 WebApplicationContext servletAppContext = createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() did not return an application " + "context for servlet [" + servletName + "]"); //封装WebApplicationContext到FrameworkServlet中。 FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); Assert.notNull(registration, "Failed to register servlet with name '" + servletName + "'." + "Check if there is another servlet registered under the same name."); registration.setLoadOnStartup(1); registration.addMapping(getServletMappings()); registration.setAsyncSupported(isAsyncSupported()); Filter[] filters = getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { registerServletFilter(servletContext, filter); } } customizeRegistration(registration); }
在registerDispatcherServlet(ServletContext servletContext)方法中创建SpringMVC的容器servletAppContext并把些容器封装到FrameworkServlet类中。方便后继在SpringMVC中使用。
Servlet容器启动时,会初始化ContextLoaderListener监听器的contextInitialized()方法。contextInitialized()方法中会取得ServletContextEvent事件并调用父类ContextLoader中的initWebApplicationContext()方法。在类中configureAndRefreshWebApplicationContext()方法会刷新容器。最后把Spring的容器WebApplicationContext保存到ServletContext及本地缓存中(currentContextPerThread)。代码如下:
ContextLoaderListener类
[code]public void contextInitialized(ServletContextEvent event) { //执行父类中的initWebApplicationContext initWebApplicationContext(event.getServletContext()); }
ContextLoader类
[code]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!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { this.context = createWebApplicationContext(servletContext); } 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); } //刷新容器,初始化Spring中的所有的Bean configureAndRefreshWebApplicationContext(cwac, servletContext); } } //ServletContext保存Spring容器WebApplicationContext. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { //保存到本地缓存 currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }
初始化SpringMVC
Servlet容器会执行HttpServletBean(DispatcherServlet的父类,HttpServlet的子类)的初始化init()方法。在init()方法中会调用initServletBean()(在HttpServletBean子类FrameworkServlet类中实现)方法。在initServletBean()方法中有一个重要的方法initWebApplicationContext(),此方法是设置Spring容器和SpringMVC容器父子关系的重要方法。在此方法中,会在ServletContext中取出Spring容器把它设置为SpringMVC的父容器。最后刷新SpringMVC容器。代码如下:
HttpServletBean类
[code]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. //调用子类FrameworkServlet中的initServletBean()方法 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
FrameworkServlet类
[code]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 { //设置Spring容器为SpringMVC的父容器 this.webAp 1b5d8 plicationContext = 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"); } } protected WebApplicationContext initWebApplicationContext() { //在ServletContext中取出Spring容器 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it //SpringMVC容器, 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 //设置Spring容器为SpringMVC容器的父容器 cwac.setParent(rootContext); } //刷新SpringMVC容器,初始化SpringMVC容器的Bean 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. //初始化DispatcherServlet中的各种Bean,设置各种配置,为后继的请求所用。 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; }
DispatcherServlet类
[code]protected void onRefresh(ApplicationContext context) { //初始化DispatcherServlet中的各种Bean,设置各种配置,为后继的请求所用。 initStrategies(context); } protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
以上为Spring,SpringMVC初始化的流程及相关代码。
- Spring之SpringMVC(源码)启动初始化过程分析
- Spring之SpringMVC的RequestToViewNameTranslator(源码)分析
- springMVC源码分析--容器初始化(二)DispatcherServlet
- SpringMVC源码分析--容器初始化(四)FrameworkServlet
- (Spring源码解析)一步一步分析,springMVC项目启动过程(一)
- Spring源码分析3----SpringMVC的设计与实现和视图的呈现
- Spring源码分析4 — spring bean创建和初始化
- Spring IOC 容器源码分析 - 余下的初始化工作
- 源码分析:SpringMVC初始化。
- springMVC源码分析--容器初始化(二)DispatcherServlet
- SpringMVC源码分析--容器初始化(四)FrameworkServlet
- SpringMVC源码分析(2)DispatcherServlet的初始化
- Spring 初始化过程详细分析[源码](一)
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
- springmvc工作原理以及源码分析(基于spring3.1.0)
- springmvc工作原理以及源码分析(基于spring3.1.0)
- 小编教您Spring源码分析之IoC容器初始化
- springMVC源码分析--容器初始化(一)ContextLoaderListener
- Spring初始化过程源码分析(1)
- (Spring源码解析)一步一步分析,springMVC项目启动过程(二)