天天看点

SpringMVC源码 2 WebApplicationContext

SpringMVC源码 2 WebApplicationContext

1.上文总结: 上一篇中讲了一些,关于SpringMVC 在Servlet容器启动过程中ServletContext的构建,以及Spring中ContextLoaderListener和ContextLoader在初始化过程中的初始化流程以及创建的一些内容。 1.在Servlet容器启动的时候,创建应用全局上下文ServletContext,读取应用配置文件web.xml。<context-param>和<listener> 2.Spring  ContextLoaderListener监听器被创建,调用contextInitialized方法。进入ContextLoader的初始化过程 3.在ContextLoader的初始化过程中,首先创建了一个WebApplicationContext,然后初始化IOC。调用AbstractApplicationContext的refresh()方法。 下面会主要讲解创建WebApplicationContext的过程,初始化IOC可以去Spring AbstractApplicationContext相关的笔记中。

2.WebApplicationContext的子类

WebApplicationContext说白了就是一个上下文,一个IOC容器。只是加入了Servlet的ServletContext。 默认使用XMLWebApplicationContext 在WebApplicationCotnext主要定义了一个 public ServletContext getServletContext()的抽象方法。可以说Web应用上下文与一般Spring程序上下文的主要区别就是对Servlet容器的ServletContext操作的区别。

其中主要的子类包含了 GeneticWebApplicationContext: XmlWebApplicationContext: xml文件配置的。ContextLoad默认创建的WebApplicationContext。  <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:context="http://www.springframework.org/schema/context"      xmlns:aop="http://www.springframework.org/schema/aop" xmlns="http://www.springframework.org/schema/beans"      xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">

     <context:annotation-config />      <!-- 自动扫描 -->      <context:component-scan base-package="com.maodq" use-default-filters="true">            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>      </context:component-scan>

     <bean id="captcha" class="com. maodq .web.Captcha" >            <property name="yunSuCaptcha" ref="yunSuCaptcha" />            <property name="juHe" ref="juHe" />      </bean>

     <bean id="yunSuCaptcha" class="com. maodq .util.YunSuCaptcha" />      <bean id="juHe" class="com. maodq .util.JuHe" />

     <context:property-placeholder location="classpath*:*.properties" />

</beans> GroovyWebApplicationContext:groovy文件配置的。 AnnotationConfigWebApplicationContext : 注解形式的web应用上下文。 @Configuration @ComponentScan("com.myhexin") @PropertySource({"classpath:redis.properties","classpath:dev.properties"      ,"classpath:http.properties","classpath:dubbo.properties","classpath:captcha.properties"}) @ImportResource({"classpath:provider.xml","classpath:consumer.xml","classpath:shutdown.xml"}) public class SpringConfig {

    @Bean     public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {         return new PropertySourcesPlaceholderConfigurer();     } }

1层 public interface  WebApplicationContext  extends ApplicationContext {      定义了一些常量,主要是String SCOPE_XXXXX和 String XXXX_XXXX_BEAN_BAME      定义了一个抽象方法,获取ServletContext     ServletContext getServletContext();

子接口ConfigurableWebApplicationContext 2层 public interface  ConfigurableWebApplicationContext  extends WebApplicationContext, ConfigurableApplicationContext      定义了两个常量: 上下文的前缀:"WebApplicationContext"   和 ServletConfig的bean名称      String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + ":";      String SERVLET_CONFIG_BEAN_NAME = "servletConfig";      定义了8个抽象方法:主要是对ServletContext Set操作。ServletConfig的Get/Set操作。 对ConfigLocation(配置文件的路径)的Get/Set操作      void setServletContext(ServletContext servletContext);      void setServletConfig(ServletConfig servletConfig);      ServletConfig getServletConfig();      void setNamespace(String namespace);      String getNamespace();      void setConfigLocation(String configLocation); ConfigLocation来自于web.xml中的参数。可以参看笔记:SpringMVC高级 1 ContextLoaderListener和Servlet容器web.xml配置.当然一些具体的WebApplicationCOntext子类中有默认的配置文件路径。例如XmlWebApplicationContext配置文件默认路径是 /WEB-INF/applicationContext.xml      void setConfigLocations(String... configLocations);      String[] getConfigLocations();   3层 public class  GenericWebApplicationContext  extends GenericApplicationContext            implements ConfigurableWebApplicationContext, ThemeSource         定义了2个变量      private ServletContext servletContext;      private ThemeSource themeSource;     还定义了一些对ServletConfig、ServletContext等的getter和setter 3层 public abstract class  AbstractRefreshableWebApplicationContext  extends AbstractRefreshableConfigApplicationContext         implements ConfigurableWebApplicationContext, ThemeSource      定义了四个变量。这四个就是WebApplicationContext与Servlet容器交互的变量。也是与常规上下文最重要的区别。      private ServletContext servletContext;      private ServletConfig servletConfig;      private String namespace;      private ThemeSource themeSource;      还定义了一些对ServletConfig、ServletContext等的getter和setter AbstractRefreshableWebApplicationContext(){      setDisplayName("Root WebApplicationContext")  //displayName设置为 Root WebApplicationContext }

  4层 public  class  XmlWebApplicationContext  extends  AbstractRefreshableWebApplicationContext {      定义3个常量。关于XML的。1.默认配置文件路径。2.默认配置文件前缀(文件目录)  3.默认配置文件后缀(文件类型xml)      public  static  final  String  DEFAULT_CONFIG_LOCATION  =  "/WEB-INF/applicationContext.xml" ;       public  static  final  String  DEFAULT_CONFIG_LOCATION_PREFIX  =  "/WEB-INF/" ;       public  static  final  String  DEFAULT_CONFIG_LOCATION_SUFFIX  =  ".xml" ; 4层 public  class  AnnotationConfigWebApplicationContext  extends  AbstractRefreshableWebApplicationContext             implements  AnnotationConfigRegistry  AnnotationConfigWebApplicationContext和 AnnotationConfigApplicationContext都实现了这个接口      定义4个常量。关于注解的。1  2   3.注解类  4.扫描的包       private  BeanNameGenerator  beanNameGenerator ;       private  ScopeMetadataResolver  scopeMetadataResolver ;       private  final  Set < Class <?>>  annotatedClasses  =  new  LinkedHashSet < Class <?>> () ;       private  final  Set < String >  basePackages  =  new  LinkedHashSet < String > () ; 4层 public  class  GroovyWebApplicationContext  extends  AbstractRefreshableWebApplicationContext           implements  GroovyObject       定义3个常量。关于groovy的。性质和XML差不多      public  static  final  String  DEFAULT_CONFIG_LOCATION  =  "/WEB-INF/applicationContext.groovy" ;      public  static  final  String  DEFAULT_CONFIG_LOCATION_PREFIX  =  "/WEB-INF/" ;      public  static  final  String  DEFAULT_CONFIG_LOCATION_SUFFIX  =  ".groovy" ;

  3.WebApplicationContext的创建细节

this.context = createWebApplicationContext(servletContext);  //开始创建WebApplicationcontext。 protected WebApplicationContext createWebApplicationContext(ServletContext sc) {       //根据ServletContext中“contextClass”的参数去创建对应的WebApplication,如果没有这个参数,则通过去加载ContextLoader.properties文件中的默认参数。(XMLWebApplicationContext)      Class<?> contextClass =  determineContextClass (sc);       //需要是ConfigurableWebApplicationContext的子类      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) { //CONTEXT_CLASS_PARAM="contextClass" 从ServletContext(web.xml)中获取“contextClass”的全类名param。 //如果这个参数不存在,会去defaultStrategies中加载数据。 //在ContextLoader中有一段代码,用来创建 defaultStrategies。通过 读取类同级目录下的ContextLoader.properties文件。文件内容如下 //org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext //这样通过获取了一个WebApplication 的全类名,通过反射的方式创建了实例      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 {                 return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());            }catch (ClassNotFoundException ex) {                 throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);            }      } }

     private static final Properties defaultStrategies;      static {            try {                 ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);                 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);            }catch (IOException ex) {                 throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());            }      } configureAndRefreshWebApplicationContext(cwac, servletContext);  //配置和刷新web应用上下文,这才是启动sprigIoc的关键 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {      if (ObjectUtils.identityToString(wac).equals(wac.getId())) {   //设置上下文的id。CONTEXT_ID_PARAM=“contextId”            String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);            if (idParam != null) {                 wac.setId(idParam);            }else {                 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +   //默认id                           ObjectUtils.getDisplayString(sc.getContextPath()));            }      }      wac.setServletContext(sc);   //对WebApplication设置Servlet容器的ServletContext。      String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);      if (configLocationParam != null) {            wac.setConfigLocation(configLocationParam);   //配置spring的配置文件路径   XmlWebApplicationContext默认为  “/WEB-INF/applicationContext.xml”      }       // The wac environment's #initPropertySources will be called in any case when the context      // is refreshed; do it eagerly here to ensure servlet property sources are in place for      // use in any post-processing or initialization that occurs below prior to #refresh      ConfigurableEnvironment env = wac.getEnvironment();      if (env instanceof ConfigurableWebEnvironment) {            ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);      }      customizeContext(sc, wac);       wac.refresh();   刷新上线文,具体上下文初始化操作,可以看AbstractApplicationContext.refresh()。 }

web.xml <context-param>      <param-name>contextConfigLocation</param-name>      <param-value>classpath:applicationContext.xml</param-value> </context-param> <context-param>      <param-name>contextClass</param-name>      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </context-param> <context-param>      <param-name>contextId</param-name>      <param-value>MMM-WebApplicationContext</param-value> </context-param> <listener>      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

SpringMVC源码 2 WebApplicationContext

参考  http://www.cnblogs.com/brolanda/p/4265597.html