Spring容器是生成Bean的工厂,我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个监听器,在项目启动时将首页的数据查询出来放到application里,即在监听器里调用后台商品业务逻辑的方法,也就是说我们需要在监听器里获取Spring中配置的相应的bean。先把监听器创建出来:

1. 创建InitDataListener

创建一个监听器InitDataListener继承ServletContextListener:

 //@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
public class InitDataListener implements ServletContextListener { private ProductService productService = null;//productService中定义了跟商品相关的业务逻辑 @Override
public void contextDestroyed(ServletContextEvent event) { } @Override
public void contextInitialized(ServletContextEvent event) { } }

并在web.xml中配置该监听器:

如上,productService中定义了商品的一些业务逻辑,并且这个productService是交给Spring管理的,那么我们如何得到这个对象呢?首先肯定的一点是:我们不能自己new出来,因为new出来的话就跟Spring的IoC没有关系了……主要有三种方式可以实现,我们先一个个分析,最后比较优劣。

2. 直接加载beans.xml文件

这种方式比较简单粗暴,不是要加载配置文件么?那好,我加载就是了,如下:

 //@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
public class InitDataListener implements ServletContextListener { private ProductService productService = null; //productService中定义了跟商品相关的业务逻辑 @Override
public void contextDestroyed(ServletContextEvent event) { } @Override
public void contextInitialized(ServletContextEvent event) {
// 获取业务逻辑类productService查询商品信息
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
productService = (ProductService) context.getBean("productService");
System.out.println(productService); //输出看看拿到了没有 //下面是具体productService相关操作……
} }

这种方法完全没问题,思路很清晰,先加载配置文件beans.xml,然后获取bean,但是启动tomcat后,我们看看控制台输出的信息:

到这里应该发现这种方式的弊端了,加载了两次配置文件,也就是说那些bean被实例化了两次,从打印的信息来看,是拿到我们自己加载配置文件是实例化的bean。这种方式明显不可取。

3. 从ServletContext中获取

从上面的方法中,我们最起码可以知道,Spring通过自己的监听器已经加载过一次配置文件了,我们没必要再加载一次,那么很容易想到,如果知道Spring加载后放到哪里了,那我们就可以从那地方获取该配置文件,下面我们看下Spring加载配置文件的过程:

上图中(省略了无关的代码),ContextLoaderListener就是web.xml中我们配置的Spring监听器,它也实现了ServletContextListener并继承了ContextLoader。在监听器中主要通过initWebApplicationContext方法来获取配置文件,并创建WebApplicationContext对象,在initWebApplicationContext方法里主要做两件事:一是拿到Spring的上下文,二是把Spring上下文放到ServletContext中,并且键为:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。那么如何拿到Spring的上下文呢?是通过获取web.xml中配置的Spring的路径,CONFIG_LOCATION_PARM其实是个字符串常量,就是上面web.xml中配置Spring监听器下面的:

<context-param>
<param-name>contextConfigLocation</param-name> <!--CONFIG_LOCATION_PARM就是contextConfigLocation-->
<param-value>classpath:beans.xml</param-value>
</context-param>

     所以就很明显了,通过web.xml中配置的路径拿到beans.xml,然后加载这个配置文件,实例化bean。

现在我们既然知道了Spring在加载配置文件后,把它放在了ServletContext中,那么我们就可以去这里面直接拿!

 //@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
public class InitDataListener implements ServletContextListener { private ProductService productService = null; @Override
public void contextDestroyed(ServletContextEvent event) {
// TODO Auto-generated method stub } @Override
public void contextInitialized(ServletContextEvent event) {
// 获取业务逻辑类查询商品信息 // 解决方案二,项目在启动时,把Spring配置文件通过Spring的监听器加载,存储到ServletContext中,我们只要在ServletContext中获取即可。
ApplicationContext context = (ApplicationContext) event.getServletContext()
.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
productService = (ProductService) context.getBean("productService");
System.out.println(productService);
} }

这样我们就可以拿到produceService的实例化对象了,这种方法好是好,就是getAttribute中的参数太长,也不知道当时程序员的脑门子被夹了还是咋地,估计是想不到其他更合适的名字了吧~

4. 通过Spring提供的工具类加载

也许开发Spring的大牛们也意识到了这个参数名字太长了,于是他们提供了一个方法类,可以加载配置文件:

 public class InitDataListener implements ServletContextListener {  

     private ProductService productService = null;  

     @Override
public void contextDestroyed(ServletContextEvent event) {
// TODO Auto-generated method stub } @Override
public void contextInitialized(ServletContextEvent event) {
// 获取业务逻辑类查询商品信息 WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
productService = (ProductService) context.getBean("productService");
System.out.println(productService);
} }

其实,这里的getWebApplicationContext方法就是把上面的那个方法封装了一下而已,我们看看这个方法的源码就知道了:

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}

这样更加方便程序员调用,仅此而已……所以一般我们使用第三种方法来获取Spring的配置文件,从而获取相应的实例化bean。

参考文章:http://blog.csdn.net/eson_15/article/details/51373937

----更多文章请看:http://blog.csdn.net/eson_15

代码实践:

Spring整合web项目时的问题:
启动服务器之后:
访问action时,每次访问都会重新加载spring配置文件,效率低下

解决方法:在服务器启动的时候,利用监听器只加载一次spring配置文件即可。

在spring里边不需要自己写代码实现,框架已经做好了封装
只需要配置即可:但是配置监听器时,需要导入一个spring整合web项目的jar包

创建一个web项目,要求每次访问action都无需加载新的xml文件,利用框架的监听器实现只在服务器启动时加载一次xml配置,用于提高性能

开发准备,导入struts相关jar和spring框架IOC相关jar以及spring整合web项目的jar包

第一种自己完成监听器的代码(不推荐,纯属娱乐)

 package org.lister;

 import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Lis implements ServletContextListener { public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub }
public void contextInitialized(ServletContextEvent arg0) {
// TODO Auto-generated method stub
//服务器启动的时候创建ApplicationContext对象
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); //得到ServletContext对象
ServletContext sc=arg0.getServletContext(); //保存创建的ApplicationContext对象,在action中调用
sc.setAttribute("applicationcontext",ac);
}
}
 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- struts过滤器配置 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com.mycompany.myapp.actions</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- 自己的监听器配置 -->
27 <listener>
28 <listener-class>org.lister.Lis</listener-class>
29 </listener> </web-app>
 package org.model;

 public class User {
public void add(){
System.out.println("add。。。。。。。。。。。。");
}
}
 package org.action;

 import java.util.Map;

 import javax.servlet.ServletContext;
import org.apache.struts2.ServletActionContext;
import org.model.User;
import org.springframework.context.ApplicationContext; import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { @Override
public String execute() throws Exception {
System.out.println("进入action");
// ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
// User user=(User)ac.getBean("user");
// user.add(); //得到ServletContext(上下文对象,即application对象)对象 并且得到里边保存的applicationContext对象;
ServletContext servletContext = ServletActionContext.getServletContext();
ApplicationContext ac=(ApplicationContext) servletContext.getAttribute("applicationcontext");
if(ac!=null){
User u=(User) ac.getBean("user");
u.add();
} /*
//以下代码也能实现
ActionContext actioncontext=ActionContext.getContext();
Map application=actioncontext.getApplication();
ApplicationContext ac2=(ApplicationContext) application.get("applicationcontext");
if(ac2!=null){
User u2=(User) ac2.getBean("user");
u2.add();
}
*/
return NONE;
}
}
 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="org.model.User"></bean>
</beans>

在上边的程序中没有配置spring框架的监听器,只配置了自己定义的,所以也实现了题目要求的功能:

服务器启动的时候加载了配置文件:

然后访问action截图如下:

即使反复请求,只会输出以上两句,控制台并没有打印其他内容,说明xml文件只加载了一次。

第二种:使用框架提供的监听机制,我们只需要配置即可,不多说 直接上代码

 package org.dao;

 public class UserDao {
public void add(){
System.out.println("UserDao.........");
}
}
 package org.service;

 import org.dao.UserDao;

 public class Service {
private UserDao userdao; public void setUserdao(UserDao userdao) {//使用set注入
this.userdao = userdao;
} public void add(){
System.out.println("Service.........");
userdao.add();
}
}
 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>actionPackages</param-name>
<param-value>com.mycompany.myapp.actions</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> 24 <!-- 使用框架提供的监听机制 需要配置下面代码 -->
25 <listener>
26 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
27 </listener>
28
29 <context-param>
30 <param-name>contextConfigLocation</param-name>
31 <param-value>classpath:applicationContext.xml</param-value>
32 </context-param>
</web-app>
 <?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="ud" class="org.dao.UserDao"></bean> <bean id="us" class="org.service.Service">
<property name="userdao" ref="ud"></property>
</bean> </beans>

 package org.action;

 import java.util.Map;

 import javax.servlet.ServletContext;

 import org.apache.struts2.ServletActionContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import com.opensymphony.xwork2.ActionSupport; import org.service.*;
public class UserAction extends ActionSupport { @Override
public String execute() throws Exception {
//ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); //得到servletContext对象(上下文application对象)
ServletContext sc=ServletActionContext.getServletContext(); //从上下文对象中取得在服务器启动时创建的ApplicationContext对象
//因为在服务器启动的时候就创建了一个applicationContext对象 并且保存在了ServletContext中(上下文application中),
//并且键为:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
ApplicationContext ac=(ApplicationContext)sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if(ac!=null){
Service s=(Service)ac.getBean("us");
s.add();
}else{
System.out.println("没有取得ApplicationContext对象");
}
/*
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());
if(ac!=null){
Service s=(Service)context.getBean("us");
s.add();
}else{
System.out.println("没有取得ApplicationContext对象");
}
*/
return NONE;//不做任何的返回
}
}


启动服务器:

反复访问action:

效果和上面的一样,没有反复加载xml生成Spring容器

-------------------------------

欢迎大家转载,但请注明原创链接:http://www.cnblogs.com/Joke-Jay/p/6507171.html

监听器如何获取Spring配置文件(加载生成Spring容器)的更多相关文章

  1. Spring配置文件加载流程

    http://blog.csdn.net/dy_paradise/article/details/6038990

  2. spring配置加载2次实例问题。

    WEB.XML 中SPRING 配置及重复加载问题 Posted on 2012-11-13, 15:48, by tmser, under java 周边 . 项目内存溢出,mat 查看了一下发现s ...

  3. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  4. Spring Boot 2.4.0正式发布,全新的配置文件加载机制(不向下兼容)

    千里之行,始于足下.关注公众号[BAT的乌托邦],有Spring技术栈.MyBatis.JVM.中间件等小而美的原创专栏供以免费学习.分享.成长,拒绝浅尝辄止.本文已被 https://www.you ...

  5. Spring中加载xml配置文件的六种方式

    Spring中加载xml配置文件的六种方式 博客分类: Spring&EJB XMLSpringWebBeanBlog  因为目前正在从事一个项目,项目中一个需求就是所有的功能都是插件的形式装 ...

  6. Spring使用环境变量控制配置文件加载

    项目中需要用到很多配置文件,不同环境的配置文件是不一样的,因此如果只用一个配置文件,势必会造成配置文件混乱,这里提供一种利用环境变量控制配置文件加载的方法,如下: 一.配置环境变量 如果是window ...

  7. Spring中加载配置文件的方式

    原文:http://blog.csdn.net/snowjlz/article/details/8158560 Spring 中加载XML配置文件的方式,好像有3种, XML是最常见的Spring 应 ...

  8. Spring如何加载log4j配置文件

    今天有朋友在群里问了这个问题,于是写了这篇文章进行整理. 问题如下: 在项目中添加了log4j.properties配置文件,并没有在Spring配置文件中配置,也没有在web.xml中配置,但是代码 ...

  9. Spring Boot加载配置文件

    问题1:Spring如何加载配置,配置文件位置? 1.默认位置: Spring Boot默认的配置文件名称为application.properties,SpringApplication将从以下位置 ...

随机推荐

  1. javaEE开发中使用session同步和token机制来防止并发重复提交

    javaEE开发中使用session同步和token机制来防止并发重复提交 通常在普通的操作当中,我们不需要处理重复提交的,而且有很多方法来防止重复提交.比如在登陆过程中,通过使用redirect,可 ...

  2. 字符集 ISO-8859-1(1)

    HTML 4.01 支持 ISO 8859-1 (Latin-1) 字符集. ISO-8859-1 的较低部分(从 1 到 127 之间的代码)是最初的 7 比特 ASCII. ISO-8859-1 ...

  3. CentOS 7 安装 JDK

    1. 卸载旧版 1.1. 查看版本信息 java -version 1.2. 查看JDK信息 rpm -qa | grep java 1.3. 卸载 rpm -e --nodeps tzdata-ja ...

  4. Oracle 表空间迁移

    迁移表空间databump 使用databump导入导出,两个库用户必须一致,否则另一个库导入的时候会报错.所以两个库都是用helei用户. 给两个数据库的用户分别授予dba权限,这里只是实验更清晰而 ...

  5. ImageView及其子类(一)

    ImageView继承自View组件,它的主要功能是用于显示图片——实际上这个书法不太严谨因为他能显示的不仅是图片,任何Drawable对象都可以使用ImageView来显示.除此之外,ImageVi ...

  6. WPF中将16进制颜色码转换成SolidColorBrush

    使用ColorConverter.ConvertFromString(string colorValue)方法 例如:new SolidColorBrush((Color)ColorConverter ...

  7. Linux内存管理之slab分配器

    slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...

  8. web前端性能调优(二)

    项目经过第一波优化之后APP端已基本已经符合我们的要求了,但是TV端还是反应比较慢,页面加载和渲染都比较慢了一点,我觉的还是有必要在进行一些优化,经过前面的优化,我们的优化空间已经小了一部分,不过还是 ...

  9. 本地ssh连接到vbox中的linux

    本机是window xp系统, 安装vbox,在vbox下安装linux,想在xp中用ssh连接linux,此时需要配置网络. 1.设置vbox的网络,选择host-only 2.设置window虚拟 ...

  10. office如何去除多页签

    写文档会遇到同时打开多个文档,偶尔可能需要对比,而有时office会出现跟浏览器类似的多页签界面.如何去除多页签,office本身没有此加载项,一般都是作为插件或组件形式另外安装,导致我们不知道从哪里 ...