基本概念:

servletContext:http://blog.csdn.net/yjw757174266/article/details/45072975

1、  使用ContextLoaderListener监听器的意义:

a) 为了在servlet容器启动时,就加载applicationContext.xml(spring核心配置文件)配置文件,实例化其中配置的bean类。

b)避免在使用spring容器获取bean时,重复加载配置文件。

2、  spring版本:4.2.4

3、  配置方式:

a)在web.xml文件中编写监听器,并配置全局的上下文变量,提供spring核心配置文件,代码如下:

<listener>

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

</listener>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext.xml</param-value>

</context-param>

b) 如果配置了监听器,那么获取bean的方式就要相应的改变一下,代码如下:

1、ServletContext servletContext = ServletActionContext.getServletContext();

2、WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

3、XXXService cs = (XXXService) context.getBean("XXXService");

4、cs.save();

c)我们先不管为什么WebApplicationContext对象与ApplicationContext对象一样能获取bean对象,我们此处探究的是,为什么配置了监听器,我们就能从servletcontext中取得WebApplicationContext对象。

4、  源码分析:

a)首先进入org.springframework.web.context.ContextLoaderListener 源码:代码如下:

//: org.springframework.web.context.ContextLoaderListener.java

package org.springframework.web.context;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

public ContextLoaderListener() {

}

public ContextLoaderListener(WebApplicationContext context) {

super(context);

}

@Override

public void contextInitialized(ServletContextEvent event) {

initWebApplicationContext(event.getServletContext());

}

@Override

public void contextDestroyed(ServletContextEvent event) {

closeWebApplicationContext(event.getServletContext());

ContextCleanupListener.cleanupAttributes(event.getServletContext());

}

}

b)我们可以看到此处继承了 ServletContextListener 接口,实现两个方法(contextInitialized、contextDestroyed),在servlet容器启动和销毁的时候做一些事情。

c) 在ContextLoaderListener监听器这个场景下,contextInitialized方法中会调用ContextLoader 类中的initWebApplicationContext方法,实例化出一个WebApplicationContext对象,此方法接收一个servletContext对象,此对象由Servlet容器传入。

5、  然后我们转到initWebApplicationContext方法中:代码如下:

//: org.springframework.web.context.ContextLoader.java

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {

throw new IllegalStateException(

"Cannot initialize context because there is already a root application context present - " +

"check whether you have multiple ContextLoader* definitions in your web.xml!");

}

Log logger = LogFactory.getLog(ContextLoader.class);

servletContext.log("Initializing Spring root WebApplicationContext");

if (logger.isInfoEnabled()) {

logger.info("Root WebApplicationContext: initialization started");

}

long startTime = System.currentTimeMillis();

try {

// Store context in local instance variable, to guarantee that

// it is available on ServletContext shutdown.

if (this.context == null) {

this.context = createWebApplicationContext(servletContext);

}

if (this.context instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent ->

// determine parent for root web application context, if any.

ApplicationContext parent = loadParentContext(servletContext);

cwac.setParent(parent);

}

configureAndRefreshWebApplicationContext(cwac, servletContext);

}

}

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);

}

if (logger.isDebugEnabled()) {

logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");

}

if (logger.isInfoEnabled()) {

long elapsedTime = System.currentTimeMillis() - startTime;

logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");

}

return this.context;

}

catch (RuntimeException ex) {

logger.error("Context initialization failed", ex);

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);

throw ex;

}

catch (Error err) {

logger.error("Context initialization failed", err);

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);

throw err;

}

}

 

a)  this.context = createWebApplicationContext(servletContext);首先我们看这句代码,同样我们先不谈就它是怎么创建的,我们见名知意,就是根据servletContext参数,创建一个WebApplicationContext对象,并赋值给ContextLoader类中的内部变量 context。

b) servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); 紧接着将已经赋值的context变量,通过一个的标识名称放入servletContext对象中。

c) 看到这里,我想大家都知道为什么可以从ServletContex中取出WebApplicationContext对象了吧?

6、  接着我们分析在客户端获取WebApplicationContext对象的代码,再copy一份到这里:

1、ServletContext servletContext = ServletActionContext.getServletContext();

2、WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

3、XXXService cs = (XXXService) context.getBean("XXXService");

4、cs.save();

a) 首先,我们从struts2框架提供的类中,获取servletContext对象。

b) 之后通过WebApplicationContextUtil类中的getWebApplicationContext方法,从servletContext对象中,将WebApplicationContext对象取出:我们进入方法:

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {

return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  // 此处标识与存入时的一致

}

c) 进而转入如下方法:

public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {

Assert.notNull(sc, "ServletContext must not be null");

Object attr = sc.getAttribute(attrName);

if (attr == null) {

return null;

}

if (attr instanceof RuntimeException) {

throw (RuntimeException) attr;

}

if (attr instanceof Error) {

throw (Error) attr;

}

if (attr instanceof Exception) {

throw new IllegalStateException((Exception) attr);

}

if (!(attr instanceof WebApplicationContext)) {

throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);

}

return (WebApplicationContext) attr;

}

d) 我们根据上面的两句代码: Object attr = sc.getAttribute(attrName);  / return (WebApplicationContext) attr; 不难看出,将WebApplicationContext对象,从servletcontext对象中取出,强制转换并返回。

7、至此

a) 我们就取得了WebApplicationContext对象,并可以使用该对象来获取bean。而WebApplicationContext对象存放在servletcontext对象中,而servletcontext对象会一直存在于内存中,除非关闭servlet容器。这样就保证了只存在一份WebApplicationContext对象在内存中,同时也就保证了spring核心配置文件只会被加载一次。

ContextLoaderListener - 运行原理的更多相关文章

  1. iis6.0与asp.net的运行原理

    这几天上网翻阅了不少前辈们的关于iis和asp.net运行原理的博客,学的有点零零散散,花了好长时间做了一个小结(虽然文字不多,但也花了不少时间呢),鄙人不才,难免有理解不道的地方,还望前辈们不吝赐教 ...

  2. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  3. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  4. 场景9 深入RAC运行原理

    场景9 深入RAC运行原理 OPS(Oracle Parallel Server)通过磁盘的节点判定数据是否最新   —>   Data Guard   —>    RAC(Real Ap ...

  5. Camel运行原理分析

    Camel运行原理分析 以一个简单的例子说明一下camel的运行原理,例子本身很简单,目的就是将一个目录下的文件搬运到另一个文件夹,处理器只是将文件(限于文本文件)的内容打印到控制台,首先代码如下: ...

  6. Web程序的运行原理及流程(一)

    自己做Web程序的开发也有两年多了 从最开始跟风学框架  到第一用上框架的欣喜若狂 我相信每个程序员都是这样过来的 在大学学习一门语言 学会后往往很想做一个实际的项目出来  我当时第一次做WEB项目看 ...

  7. Asp.net WebPages框架运行原理浅析(转)

    在Asp.net4和4.5中,新增了WebPages Framework,编写页面代码使用了新的Razor语法,代码更加的简洁和符合Web标准,编写方式更接近于PHP和以前的Asp,和使用 WebFo ...

  8. ASP.NT运行原理和页面生命周期详解及其应用

    ASP.NT运行原理和页面生命周期详解及其应用 1. 下面是我画的一张关于asp.net运行原理和页面生命周期的一张详解图.如果你对具体不太了解,请参照博客园其他帖子.在这里我主要讲解它的实际应用.  ...

  9. jsp学习--JSP运行原理,九大隐式对象和JSP常用标签

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

随机推荐

  1. 网时|细数被鹿晗热点效应带火的心机boy们

    今天上班早高峰的地铁格外的宽敞,不知道是不是因为大家都被鹿晗关晓彤的甜蜜暴击到已经忘了上班这码事了.本以为是为了新戏<甜蜜暴击>做宣传,结果工作室都相继承认,他们倒是甜蜜了,暴击全给粉丝了 ...

  2. 教你ASP.NET中如何防止注入攻击

    你应该在程序中验证所有的不信任输入.你应该假定所有的用户输入都是非法的.用户可以在应用程序中提供表单字段,查询字串,客户端cookies和浏览器环境值比如用户代理字串和IP地址等. 弱输入校验通常为注 ...

  3. jscodeshift 简易教程

    本文首发于 https://github.com/whxaxes/blog/issues/10 背景 jscodeshift 是 fb 出的一个 codemod toolkit,基于 recast 这 ...

  4. C# 动态加载卸载 DLL

    我最近做的软件,需要检测dll或exe是否混淆,需要反射获得类名,这时发现,C#可以加载DLL,但不能卸载DLL.于是在网上找到一个方法,可以动态加载DLL,不使用时可以卸载. 我在写一个WPF 程序 ...

  5. 利用大白菜制作多系统启动U盘(win+ubuntu+PE+...)

    网上提供的方法很多都过时了,不适用,要不就是讲的不清楚 我结合http://www.xuebuyuan.com/848003.html大神的方案,加以研究,整理出了此篇文章 先看下最终成果: 好了,感 ...

  6. Oracle学习笔记之PL/SQL编程

           SQL(Structure Query Language)的含义是结构化查询语句,最早由Boyce和Chambedin在1974年提出,称为SEQUEL语言.1976年,IBM公司的Sa ...

  7. 成为一名Java高级工程师你需要学什么

    宏观上: 1.技术广度方面至少要精通多门开源技术吧,研究过struts\spring等的源码.2.项目经验方面从头到尾跟过几个大项目,头是指需求阶段,包括需求调研.尾是指上线交付之后,包括维护阶段.3 ...

  8. fio2.1.10--README

    fio --- fio is a tool that will spawn a number of threads or processes doing a particular type of io ...

  9. [extjs(2)] extjs第一个组件treepanel

    刚刚在接触extjs这个前段插件,由于公司是用这个来做前段的,所以有必要花点时间来掌握一下,下面是我自己的非常浅的学习总结,后期会慢慢添加的!! 一.TreePanel基本配置参数: animate: ...

  10. EF6中使用事务的方法

    默认情况当你执行SaveChanges()的时候(insert update delete)来操作数据库时,Entity Framework会把这个操作包装在一个事务里,当操作结束后,事务也结束了. ...