基于Spring-4.3.7.RELEASE

Spring的配置不仅仅局限在XML文件,同样也可以使用Java代码来配置。在这里我使用XML配置文件的方式来粗略地讲讲WebApplicationContext。

一提到Spring,首先就应该能想到的是IoC和AOP,什么是IoC、AOP不在这里做讲解。Spring提供一个最为基础的IoC容器——BeanFactory,但这个IoC容器所能提供给我们的功能比较少,所以我们通常选用另一个——ApplicationContext(应用上下文)来作为我们的IoC容器,其实ApplicationContext也是继承自BeanFactory,只是在BeanFactory接口基础上做了扩展。那我们这篇文章里要提到的WebApplicationContext不难猜测出它是ApplicationContext的一个实现,在Web应用中我们就利用WebApplicationContext作为我们的IoC容器。

在Web应用中要使用Spring的IoC容器,首要问题就是如何将IoC容器加载到Web容器中。以下是web.xml的部分配置:

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

这段配置意为给Servlet新增一个监听器,这个监听器需要实现ServletContextListener接口,该接口中有两个方法:

public interface ServletContextListener extends EventListener {
public void contextInitialized(ServletContextEvent sce);  //ServletContext初始化的时候执行此方法
public void contextDestroyed(ServletContextEvent sce);  //ServletContext销毁的时候执行此方法
}

接着来看ContextLoaderListener:

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
} public ContextLoaderListener(WebApplicationContext context) {
super(context);
} public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
} public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}

从ContextLoaderListener可以看出WebApplicationContext的初始化实际上是由ContextListener完成的:public void initWebApplicationContext(ServletContext servletContext)

 public void initWebApplicationContext(ServletContext servletContext)
......
if(this.context == null) {
this.context = this.createWebApplicationContext(servletContext); //创建根上下文,在这之前会检查是否已经存在,如果存在则抛出IllegalStateExcpetion异常,跳到第22行
}
......
if(this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context;
if(!err.isActive()) {
if(err.getParent() == null) {
ApplicationContext elapsedTime = this.loadParentContext(servletContext);
err.setParent(elapsedTime);
}
this.configureAndRefreshWebApplicationContext(err, servletContext); //ApplicationContext上下文创建好后对其进行赋值和初始化,跳到第31行
}
}
//将WebApplicationContext根上下文绑定到Web应用程序的ServletContext上.
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
.....
return this.context;
}
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class contextClass = this.determineContextClass(sc); //判断使用什么样的类在Web容器中作为IoC容器,跳到第26行
......
}
protected Class<?> determineContextClass(ServletContext servletContext) {
String contexClassName = servlet.getInitParameter(CONTEXT_CLASS_PARAM); //读取web.xml中的配置<context-param>contextClass</context-param>
//如果配置了需要使用的CONTEXT_CLASS,那就是用这个class,如果没有额外的配置,就是用默认的ContextClass也就是XmlWebApplicationContext.
}
//设置IoC容器的参数,并通过refresh启动容器的初始化
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc){
String configLocationParam;
if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
configLocationParam = sc.getInitParameter("contextId");
if(configLocationParam != null) {
wac.setId(configLocationParam);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); //contextConfigLocation,Spring根应用上下文重要的配置文件,很多bean的定义等等
......
wac.refresh(); //启动容器的初始化
}

以上代码第27行所述web.xml中配置指定的IoC容器:

<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

以上代码第42行所述web.xml中配置指定的IoC容器:

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>

上面这段配置就是自定义要使用的IoC容器而不使用默认的XmlApplicationContext容器.

第7行代码开始,当ApplicationContext上下文建立起来过后,也就是Web应用中的IoC容器建立起来过后,接下来就是applicationContext设置一些参数例如它的双亲.至此在Web应用环境中的IoC容器就已经完成了初始化,由于要考虑Web容器的环境特别,比如各种参数的设置,所以在上面的代码能看出首先创建了IoC容器,其次再为容器赋一些参数值,最后还有IoC容器和Web容器SevletContext的结合作为全局应用上下文.在接下来会介绍在启动Spring MVC时DispatcherServert在进行自己持有的上下文的初始化时,将ApplicationContext根应用上下文设置为DispatcherServlet的双亲上下文.

Spring——Web应用中的IoC容器创建(WebApplicationContext根应用上下文的创建过程)的更多相关文章

  1. Spring学习(四)在Web项目中实例化IOC容器

    1.前言 前面我们讲到Spring在普通JAVA项目中的一些使用.本文将介绍在普通的Web项目中如何实例化Spring IOC容器.按照一般的思路.如果在Web中实例化Ioc容器.这不得获取Conte ...

  2. Spring在非web应用中关闭IoC容器 (registerShutdownHook)

    在基于web的ApplicationContext实现中,已有相应的实现来处理关闭web应用时恰当地关闭Spring IoC容器.但,如果你正在一个非web应用的环境下使用Spring的IoC容器,如 ...

  3. Spring源码分析专题 —— IOC容器启动过程(上篇)

    声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...

  4. 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建

    目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...

  5. 【spring源码分析】IOC容器初始化(总结)

    前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...

  6. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  7. 【spring源码分析】IOC容器初始化(三)

    前言:在[spring源码分析]IOC容器初始化(二)中已经得到了XML配置文件的Document实例,下面分析bean的注册过程. XmlBeanDefinitionReader#registerB ...

  8. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  9. 【spring源码分析】IOC容器初始化(七)

    前言:在[spring源码分析]IOC容器初始化(六)中分析了从单例缓存中加载bean对象,由于篇幅原因其核心函数 FactoryBeanRegistrySupport#getObjectFromFa ...

随机推荐

  1. codeforces 372E. Drawing Circles is Fun

    tags:[圆の反演][乘法原理][尺取法]题解:圆の反演:将过O点的圆,映射成不过O的直线,相切的圆反演出来的直线平行.我们将集合S中的点做反演变换:(x,y)->(x/(x^2+y^2), ...

  2. 设置ssh只允许用户从指定的IP登陆

    假设 我们公司的固定IP是  183.21.89.249   连接上我们自己进行管理的服务器   然后编辑ssh的配置文件默认  /etc/ssh/sshd_config   在文件最后面另起一行添加 ...

  3. WCF消息压缩

    对于WCF应用来说,传输前压缩请求消息和回复消息,不但可以降低网络流量,也可以提高网络传输的性能 一.消息压缩方案 二.用于数据压缩与解压缩组件 三.用于消息压缩与解压的组件 四.用于对请求/回复消息 ...

  4. 可以随鼠标拖拽的div

    可以拖拽的div <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...

  5. linux XAMPP安装与使用

    linux安装 下载好后考至目录, chmod +x  接安装包 在执行 ./ 接安装包 启动 XAMPP /opt/lampp/lampp start 停止 XAMPP /opt/lampp/lam ...

  6. JS中遍历语法的比较

    for循环 JavaScript 提供多种遍历语法.最原始的写法就是for循环.(假设myArray是数组,下面同理) let arr = [1,2,3,4,5]; for (var index = ...

  7. This Handler class should be static or leaks might occur(null) 解决办法 (转)

    原文链接:http://blog.csdn.net/wuleihenbang/article/details/17126371 首先解释下这句话This Handler class should be ...

  8. Mybatis基础学习(二)—开发Dao方式

    一.原始Dao开发方式 UserDao.java public interface UserDao{ public User findUserByID(Serializable id); public ...

  9. Java Script 数组操作

    常用几种数组操作方法: concat() join() toString() pop() push() shift() unshift() slice() splice() sort() revers ...

  10. 《深入理解Java函数式编程》系列文章

    Introduction 本系列文将帮助你理解Java函数式编程的用法.原理. 本文受启发于JavaOne 2016关于Lambda表达式的相关主题演讲Lambdas and Functional P ...