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>
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyM1ATN0EDMxEzMxEDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
参考 http://www.cnblogs.com/brolanda/p/4265597.html