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应用上下文。
/**
 * 配置spring,导入properties文件、xml文件,设置扫描范围
 */
@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>




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


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值