SpringMVC源码分析--容器初始化(四)FrameworkServlet

本文为转载,地址:http://blog.csdn.NET/qq924862077/

在上一篇博客SpringMVC源码分析--容器初始化(三)HttpServletBean我们介绍了HttpServletBean的init函数,其主要作用是初始化了一下SpringMVC配置文件的地址contextConfigLocation的配置属性,然后其调用的子类FrameworkServlet的initServletBean方法。

其实FrameworkServlet是springMVC初始化IOC容器的核心,通过读取配置的contextConfigLocation配置的springMVC配置文件的地址来读取各种初始化信息和Bean注入信息,来完成springMVC IOC 容器的初始化。接下来我们通过源码一步一步进行分析。

首先我们看initServletBean函数方法,其主要的操作就是this.webApplicationContext = initWebApplicationContext()完成webApplicationContext的初始化,webApplicationContext 即为springMVC的IOC容器,其实现类是XMLWebApplicationContext,

这样我们发现,初始化工作在initWebApplicationContext函数方法中。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.       //创建springMVC的IOC容器  
  2. @Override  
  3. protected final void initServletBean() throws ServletException {  
  4.     getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");  
  5.     if (this.logger.isInfoEnabled()) {  
  6.         this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");  
  7.     }  
  8.     long startTime = System.currentTimeMillis();  
  9.   
  10.     try {  
  11.         //创建springMVC的IOC容器  
  12.         this.webApplicationContext = initWebApplicationContext();  
  13.         //没有任何具体实现  
  14.         initFrameworkServlet();  
  15.     }  
  16.     catch (ServletException ex) {  
  17.         this.logger.error("Context initialization failed", ex);  
  18.         throw ex;  
  19.     }  
  20.     catch (RuntimeException ex) {  
  21.         this.logger.error("Context initialization failed", ex);  
  22.         throw ex;  
  23.     }  
  24.   
  25.     if (this.logger.isInfoEnabled()) {  
  26.         long elapsedTime = System.currentTimeMillis() - startTime;  
  27.         this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +  
  28.                 elapsedTime + " ms");  
  29.     }  
  30. }  
initWebApplicationContext函数方法是整个springMVC IOC实现的实现过程,函数代码段如下,

WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext())是从ServletContext中获取IOC容器,因为我们知道spring web在初始化时会将初始化的webApplicationContex保存到ServletContext中,这样我们就可以获取到spring web容器了,并且把它作为父容器。

if (this.webApplicationContext != null)  当容器已经存在时,我们就不需要重新创建,只需要刷新一下,将springMVC配置文件中的属性加载到webApplicationContext中就可以了,当不存在时我们就需要一步一步的创建webApplicationContext了。

wac = findWebApplicationContext()在ServletContext中查找WebApplicationContext,说不定它已经被存放到ServletContext中去了。

如果没有我们就需要创建wac = createWebApplicationContext(rootContext),这个步骤我们会接下来分析,创建完之后我们调用onRefresh(wac),这个方法在子类DispatcherServlet中实现,去初始化一些其他操作,现在已经完成了webApplicationContext的初始化工作了接下来就需要把webApplicationContext存放到ServletContext中去了getServletContext().setAttribute(attrName, wac),最后调用return wac完成springMVC IOC容器的初始化。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.        /** 
  2.  *初始化和发布web应用上下文,封装了建立Spring容器上下文的整个过程 
  3.  * 
  4.  */  
  5. protected WebApplicationContext initWebApplicationContext() {  
  6.     //获取由ContextLoaderListener初始化并注册在ServletContext中的根上下文,一般是Spring的IOC容器记为rootContext  
  7.     WebApplicationContext rootContext =  
  8.             WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
  9.     WebApplicationContext wac = null;  
  10.     //如果webApplicationContext已经不为空,表示这个Servlet类是通过编程式注册到容器中的(Servlet 3.0 +中的ServletContext.addServlet()),  
  11.     //上下文也由编程式传入。若这个传入的上下文还没有被初始化,将rootContext上下文设置为它的父上下文,然后将其初始化,否则直接使用。  
  12.     if (this.webApplicationContext != null) {  
  13.         // A context instance was injected at construction time -> use it  
  14.         wac = this.webApplicationContext;  
  15.         if (wac instanceof ConfigurableWebApplicationContext) {  
  16.             ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;  
  17.             if (!cwac.isActive()) {  
  18.                 // The context has not yet been refreshed -> provide services such as  
  19.                 // setting the parent context, setting the application context id, etc  
  20.                 if (cwac.getParent() == null) {  
  21.                     // The context instance was injected without an explicit parent -> set  
  22.                     // the root application context (if any; may be null) as the parent  
  23.                     cwac.setParent(rootContext);  
  24.                 }  
  25.                 configureAndRefreshWebApplicationContext(cwac);  
  26.             }  
  27.         }  
  28.     }  
  29.     //判断wac是否为空判断是否已经完成上面的上下文的设置  
  30.     if (wac == null) {  
  31.         // No context instance was injected at construction time -> see if one  
  32.         // has been registered in the servlet context. If one exists, it is assumed  
  33.         // that the parent context (if any) has already been set and that the  
  34.         // user has performed any initialization such as setting the context id  
  35.         //如果为空,说明该Servlet不是由编程式注册到容器中的,在ServletContext中查找上下文,查找得到  
  36.         //说明上下文已经以别的方式初始化并注册在contextAttribute下,直接使用  
  37.         wac = findWebApplicationContext();  
  38.     }  
  39.     if (wac == null) {  
  40.         // No context instance is defined for this servlet -> create a local one  
  41.         //此时还为空,调用以下方法创建一个全新的以rootContext为父上下文的上下文,作为SpringMVC配置元素的上下文  
  42.         //大多数情况下我们所使用的上下文就是这个新建的上下文  
  43.         wac = createWebApplicationContext(rootContext);  
  44.     }  
  45.   
  46.     if (!this.refreshEventReceived) {  
  47.         // Either the context is not a ConfigurableApplicationContext with refresh  
  48.         // support or the context injected at construction time had already been  
  49.         // refreshed -> trigger initial onRefresh manually here.  
  50.         //在DispatcherServlet中复写,会初始化一系列属性  
  51.         onRefresh(wac);  
  52.     }  
  53.   
  54.     if (this.publishContext) {  
  55.         // Publish the context as a servlet context attribute.  
  56.         //将这个上下文发布到ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键  
  57.         //设置为ServletContext的一个属性  
  58.         String attrName = getServletContextAttributeName();  
  59.         getServletContext().setAttribute(attrName, wac);  
  60.         if (this.logger.isDebugEnabled()) {  
  61.             this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +  
  62.                     "' as ServletContext attribute with name [" + attrName + "]");  
  63.         }  
  64.     }  
  65.   
  66.     return wac;  
  67. }  
上面我们介绍了springMVC IOC容器的初始化操作,但很多具体操作是在其他函数中完成的,接下来我们一一分析,

findWebApplicationContext函数是从ServletContext中查找webApplicationContext,springMVC初始化完成之后我们会看到它会将webApplicationContext保存到ServletContext中,这样我们可以在ServletContext中获取到它。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.       //从当前容器中查找SpringMVC的IOC容器  
  2. protected WebApplicationContext findWebApplicationContext() {  
  3.     String attrName = getContextAttribute();  
  4.     if (attrName == null) {  
  5.         return null;  
  6.     }  
  7.     WebApplicationContext wac =  
  8.             WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);  
  9.     if (wac == null) {  
  10.         throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");  
  11.     }  
  12.     return wac;  
  13. }  
在上面介绍中我们并没有真正介绍到webApplicationContext初始化的完整过程,其完整实现是在createWebApplicationContext函数中,其首先会实例化一个IOC容器,这只是一个空容器,并没有相关属性wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

接下来的操作就是对wac设置相关属性

wac.setEnvironment(getEnvironment())设置环境

wac.setParent(parent)设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起

wac.setConfigLocation(getContextConfigLocation())设置web.xml中的springMVC的配置文件,各种bean的注入

configureAndRefreshWebApplicationContext(wac),这个函数是关键,是解析springMVC配置文件完成初始化的过程。

return wac返回已经初始化的webApplicationContext

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.      //创建springMVC的IOC容器,  
  2. rotected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {  
  3. //获取类XMLWebApplicationContext  
  4. Class<?> contextClass = getContextClass();  
  5. if (this.logger.isDebugEnabled()) {  
  6.     this.logger.debug("Servlet with name '" + getServletName() +  
  7.             "' will try to create custom WebApplicationContext context of class '" +  
  8.             contextClass.getName() + "'" + ", using parent context [" + parent + "]");  
  9. }  
  10. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {  
  11.     throw new ApplicationContextException(  
  12.             "Fatal initialization error in servlet with name '" + getServletName() +  
  13.             "': custom WebApplicationContext class [" + contextClass.getName() +  
  14.             "] is not of type ConfigurableWebApplicationContext");  
  15. }  
  16. //实例化一个IOC容器  
  17. ConfigurableWebApplicationContext wac =  
  18.         (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
  19. //设置IOC容器相关的属性,这样springMVC的IOC容器就创建好了  
  20. wac.setEnvironment(getEnvironment());  
  21.   
  22. //设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起  
  23. wac.setParent(parent);  
  24. //设置web.xml中的springMVC的配置文件,各种bean的注入  
  25. wac.setConfigLocation(getContextConfigLocation());  
  26.   
  27. //初始化springMVC各种的相关配置,各种注入的Controller,配置文件等  
  28. configureAndRefreshWebApplicationContext(wac);  
  29.   
  30. return wac;  
上面我们介绍到configureAndRefreshWebApplicationContext函数是完成springMVC配置文件初始化过程的函数,其实它也是比较简单的,也是设置springMVC IOC容器的相关属性,

最终调用wac.refresh(),通过AbstractApplicationContext来完成对springMVC xml配置文件的解析初始化操作,这边我们就不再深入探究,在spring IOC容器初始化时我们再详细介绍。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.        /*配置或者刷新应用上下文*/  
  2. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {  
  3.     if (ObjectUtils.identityToString(wac).equals(wac.getId())) {  
  4.         // The application context id is still set to its original default value  
  5.         // -> assign a more useful id based on available information  
  6.         if (this.contextId != null) {  
  7.             wac.setId(this.contextId);  
  8.         }  
  9.         else {  
  10.             // Generate default id...  
  11.             wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +  
  12.                     ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());  
  13.         }  
  14.     }  
  15.     //设置springMVC IOC容器的相关属性  
  16.     wac.setServletContext(getServletContext());  
  17.     wac.setServletConfig(getServletConfig());  
  18.     wac.setNamespace(getNamespace());  
  19.     wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));  
  20.   
  21.     // The wac environment's #initPropertySources will be called in any case when the context  
  22.     // is refreshed; do it eagerly here to ensure servlet property sources are in place for  
  23.     // use in any post-processing or initialization that occurs below prior to #refresh  
  24.     ConfigurableEnvironment env = wac.getEnvironment();  
  25.     if (env instanceof ConfigurableWebEnvironment) {  
  26.         ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());  
  27.     }  
  28.   
  29.     postProcessWebApplicationContext(wac);  
  30.     applyInitializers(wac);  
  31.     //初始化springMVC各种的相关配置,各种注入的Controller,配置文件等  
  32.     wac.refresh();  
  33. }  
通过以上函数的操作就完成了springMVC IOC容器的初始化操作,并且把spring web初始化的IOC容器作为父容器,这样springMVC就可以获得父容器中注入的各种Bean,同时初始化的IOC容器webApplicationContext也会被存放到ServletContex中,这样在整个的web容器中都可以得到并使用IOC容器中的各种属性。

FrameworkServlet完整源码解析:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.  //FrameworkServlet类的设计目的就是用来建立一个和Servlet关联的Spring容器上下文  
  2.  //并将其注册到ServletContext中,跳脱开SpringMVC体系,我们也能通过继承FrameworkServlet类  
  3.  //得到与Spring容器整合的好处,FrameworkServlet和HttpServletBean一样,是一个可以独立使用的类  
  4.    
  5. @SuppressWarnings("serial")  
  6. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {  
  7.   
  8.     //servlet命名空间前缀  
  9.     public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";  
  10.       
  11.     //FrameworkServlet类的上下文  
  12.     public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  
  13.   
  14.     public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";  
  15.   
  16.     private static final String INIT_PARAM_DELIMITERS = ",; \t\n";  
  17.   
  18.     private static final boolean responseGetStatusAvailable =  
  19.             ClassUtils.hasMethod(HttpServletResponse.class"getStatus");  
  20.   
  21.     private String contextAttribute;  
  22.   
  23.     private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;  
  24.   
  25.     private String contextId;  
  26.   
  27.     private String namespace;  
  28.   
  29.     // web.xml中配置的contextConfigLocation属性,就是springMVC的配置文件  
  30.     private String contextConfigLocation;  
  31.   
  32.     /** Actual ApplicationContextInitializer instances to apply to the context */  
  33.     private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =  
  34.             new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();  
  35.   
  36.     /** Comma-delimited ApplicationContextInitializer class names set through init param */  
  37.     private String contextInitializerClasses;  
  38.   
  39.     /** Should we publish the context as a ServletContext attribute? */  
  40.     private boolean publishContext = true;  
  41.   
  42.     /** Should we publish a ServletRequestHandledEvent at the end of each request? */  
  43.     private boolean publishEvents = true;  
  44.   
  45.     /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */  
  46.     private boolean threadContextInheritable = false;  
  47.   
  48.     /** Should we dispatch an HTTP OPTIONS request to {@link #doService}? */  
  49.     private boolean dispatchOptionsRequest = false;  
  50.   
  51.     /** Should we dispatch an HTTP TRACE request to {@link #doService}? */  
  52.     private boolean dispatchTraceRequest = false;  
  53.   
  54.     /** WebApplicationContext for this servlet */  
  55.     private WebApplicationContext webApplicationContext;  
  56.   
  57.     /** If the WebApplicationContext was injected via {@link #setApplicationContext} */  
  58.     private boolean webApplicationContextInjected = false;  
  59.   
  60.     /** Flag used to detect whether onRefresh has already been called */  
  61.     private boolean refreshEventReceived = false;  
  62.   
  63.     public FrameworkServlet() {  
  64.     }  
  65.       
  66.     public FrameworkServlet(WebApplicationContext webApplicationContext) {  
  67.         this.webApplicationContext = webApplicationContext;  
  68.     }  
  69.   
  70.     public void setContextAttribute(String contextAttribute) {  
  71.         this.contextAttribute = contextAttribute;  
  72.     }  
  73.   
  74.     public String getContextAttribute() {  
  75.         return this.contextAttribute;  
  76.     }  
  77.   
  78.     public void setContextClass(Class<?> contextClass) {  
  79.         this.contextClass = contextClass;  
  80.     }  
  81.   
  82.     public Class<?> getContextClass() {  
  83.         return this.contextClass;  
  84.     }  
  85.   
  86.     public void setContextId(String contextId) {  
  87.         this.contextId = contextId;  
  88.     }  
  89.   
  90.     public String getContextId() {  
  91.         return this.contextId;  
  92.     }  
  93.   
  94.     public void setNamespace(String namespace) {  
  95.         this.namespace = namespace;  
  96.     }  
  97.   
  98.     public String getNamespace() {  
  99.         return (this.namespace != null ? this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);  
  100.     }  
  101.       
  102.     //web.xml中配置文件的地址  
  103.     public void setContextConfigLocation(String contextConfigLocation) {  
  104.         this.contextConfigLocation = contextConfigLocation;  
  105.     }  
  106.   
  107.     public String getContextConfigLocation() {  
  108.         return this.contextConfigLocation;  
  109.     }  
  110.   
  111.     @SuppressWarnings("unchecked")  
  112.     public void setContextInitializers(ApplicationContextInitializer<?>... initializers) {  
  113.         if (initializers != null) {  
  114.             for (ApplicationContextInitializer<?> initializer : initializers) {  
  115.                 this.contextInitializers.add((ApplicationContextInitializer<ConfigurableApplicationContext>) initializer);  
  116.             }  
  117.         }  
  118.     }  
  119.       
  120.     public void setContextInitializerClasses(String contextInitializerClasses) {  
  121.         this.contextInitializerClasses = contextInitializerClasses;  
  122.     }  
  123.   
  124.     public void setPublishContext(boolean publishContext) {  
  125.         this.publishContext = publishContext;  
  126.     }  
  127.   
  128.       
  129.     public void setPublishEvents(boolean publishEvents) {  
  130.         this.publishEvents = publishEvents;  
  131.     }  
  132.   
  133.       
  134.     public void setThreadContextInheritable(boolean threadContextInheritable) {  
  135.         this.threadContextInheritable = threadContextInheritable;  
  136.     }  
  137.   
  138.     public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {  
  139.         this.dispatchOptionsRequest = dispatchOptionsRequest;  
  140.     }  
  141.   
  142.     public void setDispatchTraceRequest(boolean dispatchTraceRequest) {  
  143.         this.dispatchTraceRequest = dispatchTraceRequest;  
  144.     }  
  145.       
  146.     @Override  
  147.     public void setApplicationContext(ApplicationContext applicationContext) {  
  148.         if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {  
  149.             this.webApplicationContext = (WebApplicationContext) applicationContext;  
  150.             this.webApplicationContextInjected = true;  
  151.         }  
  152.     }  
  153.   
  154.     //创建springMVC的IOC容器  
  155.     @Override  
  156.     protected final void initServletBean() throws ServletException {  
  157.         getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");  
  158.         if (this.logger.isInfoEnabled()) {  
  159.             this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");  
  160.         }  
  161.         long startTime = System.currentTimeMillis();  
  162.   
  163.         try {  
  164.             //创建springMVC的IOC容器  
  165.             this.webApplicationContext = initWebApplicationContext();  
  166.             //没有任何具体实现  
  167.             initFrameworkServlet();  
  168.         }  
  169.         catch (ServletException ex) {  
  170.             this.logger.error("Context initialization failed", ex);  
  171.             throw ex;  
  172.         }  
  173.         catch (RuntimeException ex) {  
  174.             this.logger.error("Context initialization failed", ex);  
  175.             throw ex;  
  176.         }  
  177.   
  178.         if (this.logger.isInfoEnabled()) {  
  179.             long elapsedTime = System.currentTimeMillis() - startTime;  
  180.             this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +  
  181.                     elapsedTime + " ms");  
  182.         }  
  183.     }  
  184.   
  185.     /** 
  186.      *初始化和发布web应用上下文,封装了建立Spring容器上下文的整个过程 
  187.      * 
  188.      */  
  189.     protected WebApplicationContext initWebApplicationContext() {  
  190.         //获取由ContextLoaderListener初始化并注册在ServletContext中的根上下文,一般是Spring的IOC容器记为rootContext  
  191.         WebApplicationContext rootContext =  
  192.                 WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
  193.         WebApplicationContext wac = null;  
  194.         //如果webApplicationContext已经不为空,表示这个Servlet类是通过编程式注册到容器中的(Servlet 3.0 +中的ServletContext.addServlet()),  
  195.         //上下文也由编程式传入。若这个传入的上下文还没有被初始化,将rootContext上下文设置为它的父上下文,然后将其初始化,否则直接使用。  
  196.         if (this.webApplicationContext != null) {  
  197.             // A context instance was injected at construction time -> use it  
  198.             wac = this.webApplicationContext;  
  199.             if (wac instanceof ConfigurableWebApplicationContext) {  
  200.                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;  
  201.                 if (!cwac.isActive()) {  
  202.                     // The context has not yet been refreshed -> provide services such as  
  203.                     // setting the parent context, setting the application context id, etc  
  204.                     if (cwac.getParent() == null) {  
  205.                         // The context instance was injected without an explicit parent -> set  
  206.                         // the root application context (if any; may be null) as the parent  
  207.                         cwac.setParent(rootContext);  
  208.                     }  
  209.                     configureAndRefreshWebApplicationContext(cwac);  
  210.                 }  
  211.             }  
  212.         }  
  213.         //判断wac是否为空判断是否已经完成上面的上下文的设置  
  214.         if (wac == null) {  
  215.             // No context instance was injected at construction time -> see if one  
  216.             // has been registered in the servlet context. If one exists, it is assumed  
  217.             // that the parent context (if any) has already been set and that the  
  218.             // user has performed any initialization such as setting the context id  
  219.             //如果为空,说明该Servlet不是由编程式注册到容器中的,在ServletContext中查找上下文,查找得到  
  220.             //说明上下文已经以别的方式初始化并注册在contextAttribute下,直接使用  
  221.             wac = findWebApplicationContext();  
  222.         }  
  223.         if (wac == null) {  
  224.             // No context instance is defined for this servlet -> create a local one  
  225.             //此时还为空,调用以下方法创建一个全新的以rootContext为父上下文的上下文,作为SpringMVC配置元素的上下文  
  226.             //大多数情况下我们所使用的上下文就是这个新建的上下文  
  227.             wac = createWebApplicationContext(rootContext);  
  228.         }  
  229.   
  230.         if (!this.refreshEventReceived) {  
  231.             // Either the context is not a ConfigurableApplicationContext with refresh  
  232.             // support or the context injected at construction time had already been  
  233.             // refreshed -> trigger initial onRefresh manually here.  
  234.             //在DispatcherServlet中复写,会初始化一系列属性  
  235.             onRefresh(wac);  
  236.         }  
  237.   
  238.         if (this.publishContext) {  
  239.             // Publish the context as a servlet context attribute.  
  240.             //将这个上下文发布到ServletContext中,也就是将上下文以一个和Servlet类在web.xml中注册名字有关的值为键  
  241.             //设置为ServletContext的一个属性  
  242.             String attrName = getServletContextAttributeName();  
  243.             getServletContext().setAttribute(attrName, wac);  
  244.             if (this.logger.isDebugEnabled()) {  
  245.                 this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +  
  246.                         "' as ServletContext attribute with name [" + attrName + "]");  
  247.             }  
  248.         }  
  249.   
  250.         return wac;  
  251.     }  
  252.   
  253.      //从当前容器中查找SpringMVC的IOC容器  
  254.     protected WebApplicationContext findWebApplicationContext() {  
  255.         String attrName = getContextAttribute();  
  256.         if (attrName == null) {  
  257.             return null;  
  258.         }  
  259.         WebApplicationContext wac =  
  260.                 WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);  
  261.         if (wac == null) {  
  262.             throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");  
  263.         }  
  264.         return wac;  
  265.     }  
  266.   
  267.      //创建springMVC的IOC容器,  
  268.     protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {  
  269.         //获取类XMLWebApplicationContext  
  270.         Class<?> contextClass = getContextClass();  
  271.         if (this.logger.isDebugEnabled()) {  
  272.             this.logger.debug("Servlet with name '" + getServletName() +  
  273.                     "' will try to create custom WebApplicationContext context of class '" +  
  274.                     contextClass.getName() + "'" + ", using parent context [" + parent + "]");  
  275.         }  
  276.         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {  
  277.             throw new ApplicationContextException(  
  278.                     "Fatal initialization error in servlet with name '" + getServletName() +  
  279.                     "': custom WebApplicationContext class [" + contextClass.getName() +  
  280.                     "] is not of type ConfigurableWebApplicationContext");  
  281.         }  
  282.         //实例化一个IOC容器  
  283.         ConfigurableWebApplicationContext wac =  
  284.                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
  285.         //设置IOC容器相关的属性,这样springMVC的IOC容器就创建好了  
  286.         wac.setEnvironment(getEnvironment());  
  287.           
  288.         //设置parent,这样就把springMVC和Spring的两个IOC容器连接了在一起  
  289.         wac.setParent(parent);  
  290.         //设置web.xml中的springMVC的配置文件,各种bean的注入  
  291.         wac.setConfigLocation(getContextConfigLocation());  
  292.           
  293.         //初始化springMVC各种的相关配置,各种注入的Controller,配置文件等  
  294.         configureAndRefreshWebApplicationContext(wac);  
  295.   
  296.         return wac;  
  297.     }  
  298.     /*配置或者刷新应用上下文*/  
  299.     protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {  
  300.         if (ObjectUtils.identityToString(wac).equals(wac.getId())) {  
  301.             // The application context id is still set to its original default value  
  302.             // -> assign a more useful id based on available information  
  303.             if (this.contextId != null) {  
  304.                 wac.setId(this.contextId);  
  305.             }  
  306.             else {  
  307.                 // Generate default id...  
  308.                 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +  
  309.                         ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());  
  310.             }  
  311.         }  
  312.         //设置springMVC IOC容器的相关属性  
  313.         wac.setServletContext(getServletContext());  
  314.         wac.setServletConfig(getServletConfig());  
  315.         wac.setNamespace(getNamespace());  
  316.         wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));  
  317.   
  318.         // The wac environment's #initPropertySources will be called in any case when the context  
  319.         // is refreshed; do it eagerly here to ensure servlet property sources are in place for  
  320.         // use in any post-processing or initialization that occurs below prior to #refresh  
  321.         ConfigurableEnvironment env = wac.getEnvironment();  
  322.         if (env instanceof ConfigurableWebEnvironment) {  
  323.             ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());  
  324.         }  
  325.   
  326.         postProcessWebApplicationContext(wac);  
  327.         applyInitializers(wac);  
  328.         //初始化springMVC各种的相关配置,各种注入的Controller,配置文件等  
  329.         wac.refresh();  
  330.     }  
  331.   
  332.     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {  
  333.         return createWebApplicationContext((ApplicationContext) parent);  
  334.     }  
  335.   
  336.     protected void postProcessWebApplicationContext(ConfigurableWebApplicationContext wac) {  
  337.     }  
  338.   
  339.     protected void applyInitializers(ConfigurableApplicationContext wac) {  
  340.         String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);  
  341.         if (globalClassNames != null) {  
  342.             for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {  
  343.                 this.contextInitializers.add(loadInitializer(className, wac));  
  344.             }  
  345.         }  
  346.   
  347.         if (this.contextInitializerClasses != null) {  
  348.             for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {  
  349.                 this.contextInitializers.add(loadInitializer(className, wac));  
  350.             }  
  351.         }  
  352.   
  353.         AnnotationAwareOrderComparator.sort(this.contextInitializers);  
  354.         for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {  
  355.             initializer.initialize(wac);  
  356.         }  
  357.     }  
  358.   
  359.     @SuppressWarnings("unchecked")  
  360.     private ApplicationContextInitializer<ConfigurableApplicationContext> loadInitializer(  
  361.             String className, ConfigurableApplicationContext wac) {  
  362.         try {  
  363.             Class<?> initializerClass = ClassUtils.forName(className, wac.getClassLoader());  
  364.             Class<?> initializerContextClass =  
  365.                     GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);  
  366.             if (initializerContextClass != null) {  
  367.                 Assert.isAssignable(initializerContextClass, wac.getClass(), String.format(  
  368.                         "Could not add context initializer [%s] since its generic parameter [%s] " +  
  369.                         "is not assignable from the type of application context used by this " +  
  370.                         "framework servlet [%s]: ", initializerClass.getName(), initializerContextClass.getName(),  
  371.                         wac.getClass().getName()));  
  372.             }  
  373.             return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class);  
  374.         }  
  375.         catch (Exception ex) {  
  376.             throw new IllegalArgumentException(String.format("Could not instantiate class [%s] specified " +  
  377.                     "via 'contextInitializerClasses' init-param", className), ex);  
  378.         }  
  379.     }  
  380.       
  381.     public String getServletContextAttributeName() {  
  382.         return SERVLET_CONTEXT_PREFIX + getServletName();  
  383.     }  
  384.   
  385.     /** 
  386.      * Return this servlet's WebApplicationContext. 
  387.      */  
  388.     public final WebApplicationContext getWebApplicationContext() {  
  389.         return this.webApplicationContext;  
  390.     }  
  391.   
  392.   
  393.     protected void initFrameworkServlet() throws ServletException {  
  394.     }  
  395.   
  396.     public void refresh() {  
  397.         WebApplicationContext wac = getWebApplicationContext();  
  398.         if (!(wac instanceof ConfigurableApplicationContext)) {  
  399.             throw new IllegalStateException("WebApplicationContext does not support refresh: " + wac);  
  400.         }  
  401.         ((ConfigurableApplicationContext) wac).refresh();  
  402.     }  
  403.   
  404.     //WebApplicationContext刷新通知  
  405.     public void onApplicationEvent(ContextRefreshedEvent event) {  
  406.         this.refreshEventReceived = true;  
  407.         onRefresh(event.getApplicationContext());  
  408.     }  
  409.   
  410.     protected void onRefresh(ApplicationContext context) {  
  411.         // For subclasses: do nothing by default.  
  412.     }  
  413.   
  414.     /** 
  415.      * Close the WebApplicationContext of this servlet. 
  416.      * @see org.springframework.context.ConfigurableApplicationContext#close() 
  417.      */  
  418.     @Override  
  419.     public void destroy() {  
  420.         getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");  
  421.         // Only call close() on WebApplicationContext if locally managed...  
  422.         if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) {  
  423.             ((ConfigurableApplicationContext) this.webApplicationContext).close();  
  424.         }  
  425.     }  
  426.   
  427.   
  428.     /** 
  429.      * Override the parent class implementation in order to intercept PATCH 
  430.      * requests. 
  431.      */  
  432.     @Override  
  433.     protected void service(HttpServletRequest request, HttpServletResponse response)  
  434.             throws ServletException, IOException {  
  435.   
  436.         String method = request.getMethod();  
  437.         if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {  
  438.             processRequest(request, response);  
  439.         }  
  440.         else {  
  441.             super.service(request, response);  
  442.         }  
  443.     }  
  444.   
  445.     //get请求  
  446.     @Override  
  447.     protected final void doGet(HttpServletRequest request, HttpServletResponse response)  
  448.             throws ServletException, IOException {  
  449.   
  450.         processRequest(request, response);  
  451.     }  
  452.   
  453.     //post请求  
  454.     @Override  
  455.     protected final void doPost(HttpServletRequest request, HttpServletResponse response)  
  456.             throws ServletException, IOException {  
  457.   
  458.         processRequest(request, response);  
  459.     }  
  460.   
  461.     //put请求  
  462.     @Override  
  463.     protected final void doPut(HttpServletRequest request, HttpServletResponse response)  
  464.             throws ServletException, IOException {  
  465.   
  466.         processRequest(request, response);  
  467.     }  
  468.   
  469.     //delete请求  
  470.     @Override  
  471.     protected final void doDelete(HttpServletRequest request, HttpServletResponse response)  
  472.             throws ServletException, IOException {  
  473.   
  474.         processRequest(request, response);  
  475.     }  
  476.   
  477.     @Override  
  478.     protected void doOptions(HttpServletRequest request, HttpServletResponse response)  
  479.             throws ServletException, IOException {  
  480.   
  481.         if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {  
  482.             processRequest(request, response);  
  483.             if (response.containsHeader("Allow")) {  
  484.                 // Proper OPTIONS response coming from a handler - we're done.  
  485.                 return;  
  486.             }  
  487.         }  
  488.   
  489.         // Use response wrapper for Servlet 2.5 compatibility where  
  490.         // the getHeader() method does not exist  
  491.         super.doOptions(request, new HttpServletResponseWrapper(response) {  
  492.             @Override  
  493.             public void setHeader(String name, String value) {  
  494.                 if ("Allow".equals(name)) {  
  495.                     value = (StringUtils.hasLength(value) ? value + ", " : "") + RequestMethod.PATCH.name();  
  496.                 }  
  497.                 super.setHeader(name, value);  
  498.             }  
  499.         });  
  500.     }  
  501.   
  502.     @Override  
  503.     protected void doTrace(HttpServletRequest request, HttpServletResponse response)  
  504.             throws ServletException, IOException {  
  505.   
  506.         if (this.dispatchTraceRequest) {  
  507.             processRequest(request, response);  
  508.             if ("message/http".equals(response.getContentType())) {  
  509.                 // Proper TRACE response coming from a handler - we're done.  
  510.                 return;  
  511.             }  
  512.         }  
  513.         super.doTrace(request, response);  
  514.     }  
  515.   
  516.     protected final void processRequest(HttpServletRequest request, HttpServletResponse response)  
  517.             throws ServletException, IOException {  
  518.   
  519.         long startTime = System.currentTimeMillis();  
  520.         Throwable failureCause = null;  
  521.   
  522.         LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();  
  523.         LocaleContext localeContext = buildLocaleContext(request);  
  524.   
  525.         RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();  
  526.         ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);  
  527.   
  528.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  529.         asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());  
  530.   
  531.         initContextHolders(request, localeContext, requestAttributes);  
  532.   
  533.         try {  
  534.             doService(request, response);  
  535.         }  
  536.         catch (ServletException ex) {  
  537.             failureCause = ex;  
  538.             throw ex;  
  539.         }  
  540.         catch (IOException ex) {  
  541.             failureCause = ex;  
  542.             throw ex;  
  543.         }  
  544.         catch (Throwable ex) {  
  545.             failureCause = ex;  
  546.             throw new NestedServletException("Request processing failed", ex);  
  547.         }  
  548.   
  549.         finally {  
  550.             resetContextHolders(request, previousLocaleContext, previousAttributes);  
  551.             if (requestAttributes != null) {  
  552.                 requestAttributes.requestCompleted();  
  553.             }  
  554.   
  555.             if (logger.isDebugEnabled()) {  
  556.                 if (failureCause != null) {  
  557.                     this.logger.debug("Could not complete request", failureCause);  
  558.                 }  
  559.                 else {  
  560.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  561.                         logger.debug("Leaving response open for concurrent processing");  
  562.                     }  
  563.                     else {  
  564.                         this.logger.debug("Successfully completed request");  
  565.                     }  
  566.                 }  
  567.             }  
  568.   
  569.             publishRequestHandledEvent(request, response, startTime, failureCause);  
  570.         }  
  571.     }  
  572.   
  573.       
  574.     protected LocaleContext buildLocaleContext(HttpServletRequest request) {  
  575.         return new SimpleLocaleContext(request.getLocale());  
  576.     }  
  577.   
  578.     protected ServletRequestAttributes buildRequestAttributes(  
  579.             HttpServletRequest request, HttpServletResponse response, RequestAttributes previousAttributes) {  
  580.   
  581.         if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {  
  582.             return new ServletRequestAttributes(request, response);  
  583.         }  
  584.         else {  
  585.             return null;  // preserve the pre-bound RequestAttributes instance  
  586.         }  
  587.     }  
  588.   
  589.     private void initContextHolders(  
  590.             HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {  
  591.   
  592.         if (localeContext != null) {  
  593.             LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);  
  594.         }  
  595.         if (requestAttributes != null) {  
  596.             RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);  
  597.         }  
  598.         if (logger.isTraceEnabled()) {  
  599.             logger.trace("Bound request context to thread: " + request);  
  600.         }  
  601.     }  
  602.   
  603.     private void resetContextHolders(HttpServletRequest request,  
  604.             LocaleContext prevLocaleContext, RequestAttributes previousAttributes) {  
  605.   
  606.         LocaleContextHolder.setLocaleContext(prevLocaleContext, this.threadContextInheritable);  
  607.         RequestContextHolder.setRequestAttributes(previousAttributes, this.threadContextInheritable);  
  608.         if (logger.isTraceEnabled()) {  
  609.             logger.trace("Cleared thread-bound request context: " + request);  
  610.         }  
  611.     }  
  612.   
  613.     private void publishRequestHandledEvent(  
  614.             HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {  
  615.   
  616.         if (this.publishEvents) {  
  617.             // Whether or not we succeeded, publish an event.  
  618.             long processingTime = System.currentTimeMillis() - startTime;  
  619.             int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);  
  620.             this.webApplicationContext.publishEvent(  
  621.                     new ServletRequestHandledEvent(this,  
  622.                             request.getRequestURI(), request.getRemoteAddr(),  
  623.                             request.getMethod(), getServletConfig().getServletName(),  
  624.                             WebUtils.getSessionId(request), getUsernameForRequest(request),  
  625.                             processingTime, failureCause, statusCode));  
  626.         }  
  627.     }  
  628.   
  629.       
  630.     protected String getUsernameForRequest(HttpServletRequest request) {  
  631.         Principal userPrincipal = request.getUserPrincipal();  
  632.         return (userPrincipal != null ? userPrincipal.getName() : null);  
  633.     }  
  634.   
  635.   
  636.     protected abstract void doService(HttpServletRequest request, HttpServletResponse response)  
  637.             throws Exception;  
  638.   
  639.     //监听WebApplicationContext的刷新情况  
  640.     private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {  
  641.   
  642.         @Override  
  643.         public void onApplicationEvent(ContextRefreshedEvent event) {  
  644.             FrameworkServlet.this.onApplicationEvent(event);  
  645.         }  
  646.     }  
  647.   
  648.     private class RequestBindingInterceptor extends CallableProcessingInterceptorAdapter {  
  649.   
  650.         @Override  
  651.         public <T> void preProcess(NativeWebRequest webRequest, Callable<T> task) {  
  652.             HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);  
  653.             if (request != null) {  
  654.                 HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);  
  655.                 initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));  
  656.             }  
  657.         }  
  658.         @Override  
  659.         public <T> void postProcess(NativeWebRequest webRequest, Callable<T> task, Object concurrentResult) {  
  660.             HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);  
  661.             if (request != null) {  
  662.                 resetContextHolders(request, nullnull);  
  663.             }  
  664.         }  
  665.     }  
  666.   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值