SpringMvc源码分析-XML初始化

1.前言

从web.xml解析SpringMvc容器初始化过程,基于Spring4.0+版本

2.web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
    /* ContextLoaderListener监听器,当tomcat启动的时候,调用其初始化方法*/
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3.ContextLoaderListener(Tomcat启动时会创建)

 1、tomcat初始化调用contextInitialized方法

@Override
public void contextInitialized(ServletContextEvent event) {
   /*传入Tomcat中servlet容器,即tomcat的上下文环境*/
   initWebApplicationContext(event.getServletContext());
}

2、initWebApplicationContext方法(去除了部分日志代码)

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
   /*防止xml中多次使用监听器初始化*/
   if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
      throw new IllegalStateException("error");
   }
   try {
      if (this.context == null) {
         /*创建IOC容器*/
         this.context = createWebApplicationContext(servletContext);
      }
      if (this.context instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
         if (!cwac.isActive()) {
            if (cwac.getParent() == null) {
               ApplicationContext parent = loadParentContext(servletContext);
               cwac.setParent(parent);
            }
            /*刷新spring容器*/
            configureAndRefreshWebApplicationContext(cwac, servletContext);
         }
      }
      /*将IOC容器放入servlet容器中*/
      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);
      }
      return this.context;
   }
}

initWebApplicationContext做了如下:

(1)调用createWebApplicationContext方法 创建springIOC容器

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
   // 获取需要创建的容器class文件地址
   Class<?> contextClass = determineContextClass(sc);
   if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
      throw new ApplicationContextException("error");
   }
   // 反射生成实例
   return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
protected Class<?> determineContextClass(ServletContext servletContext) {
   // 加载web.xml中初始化参数是否有contextClass,如果有使用此值作为contextClass
   String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
   if (contextClassName != null) {
      try {
         return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
      }
   }
   else {
      // 加载配置文件中默认contextClass(XmlWebApplicationContext),在此类static块中获取了默认配置文件
      contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
      try {
         return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
      }
   }
}
static {
   try {
      // 封装配置文件
      ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
      // 加载配置文件
      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
   }
}

 

此方法主要可以看出,可以自定义contextClass通过web.xml参数形式使用,主要就是生成了SpringIOC容器

(2)调用configureAndRefreshWebApplicationContext方法刷新springIOC容器并关联ServletContext

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
   if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
      // web.xml有默认参数那么设置默认ID
      String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
      if (idParam != null) {
         wac.setId(idParam);
      }
      else {
         // 如果没有默认参数使用默认规则创建ID
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(sc.getContextPath()));
      }
   }
   // 设置ServletContext容器
   wac.setServletContext(sc);
   // 设置获取Spring配置文件地址并设置到容器
   String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
   if (configLocationParam != null) {
      wac.setConfigLocation(configLocationParam);
   }
   ConfigurableEnvironment env = wac.getEnvironment();
   if (env instanceof ConfigurableWebEnvironment) {
      ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
   }
   customizeContext(sc, wac);
   // Spring刷新流程
   wac.refresh();
}

 (3)将IOC容器放入servlet容器中

 (4)映射类加载器和实例到全局变量至currentContextPerThread中

4.总结

ContextLoaderListener的作用:初始化spring容器,将web与spring容器相关联

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值