• 监听器如何获取Spring配置文件(加载生成Spring容器)


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

    1. 创建InitDataListener

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

     1 //@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中  
     2 public class InitDataListener implements ServletContextListener {  
     3       
     4     private ProductService productService = null;//productService中定义了跟商品相关的业务逻辑  
     5       
     6     @Override  
     7     public void contextDestroyed(ServletContextEvent event) {  
     8   
     9     }  
    10   
    11     @Override  
    12     public void contextInitialized(ServletContextEvent event) {  
    13   
    14     }  
    15   
    16 }  

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

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

    2. 直接加载beans.xml文件

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

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

      这种方法完全没问题,思路很清晰,先加载配置文件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中,那么我们就可以去这里面直接拿!

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

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

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

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

     1 public class InitDataListener implements ServletContextListener {  
     2   
     3       
     4     private ProductService productService = null;  
     5       
     6     @Override  
     7     public void contextDestroyed(ServletContextEvent event) {  
     8         // TODO Auto-generated method stub  
     9   
    10     }  
    11   
    12     @Override  
    13     public void contextInitialized(ServletContextEvent event) {  
    14         // 获取业务逻辑类查询商品信息  
    15   
    16         WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());  
    17         productService = (ProductService) context.getBean("productService");  
    18         System.out.println(productService);  
    19     }  
    20   
    21 } 

     其实,这里的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包

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

     1 package org.lister;
     2 
     3 import javax.servlet.ServletContext;
     4 import javax.servlet.ServletContextEvent;
     5 import javax.servlet.ServletContextListener;
     6 
     7 import org.springframework.context.ApplicationContext;
     8 import org.springframework.context.support.ClassPathXmlApplicationContext;
     9 
    10 public class Lis implements ServletContextListener {
    11 
    12     public void contextDestroyed(ServletContextEvent arg0) {
    13         // TODO Auto-generated method stub
    14 
    15     }
    16     public void contextInitialized(ServletContextEvent arg0) {
    17         // TODO Auto-generated method stub
    18         //服务器启动的时候创建ApplicationContext对象
    19         ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
    20         
    21         //得到ServletContext对象
    22         ServletContext sc=arg0.getServletContext();
    23         
    24         //保存创建的ApplicationContext对象,在action中调用
    25         sc.setAttribute("applicationcontext",ac);
    26     }
    27 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app version="2.5" 
     3     xmlns="http://java.sun.com/xml/ns/javaee" 
     4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
     6     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
     7   <welcome-file-list>
     8     <welcome-file>index.jsp</welcome-file>
     9   </welcome-file-list>
    10   
    11   <!-- struts过滤器配置 -->
    12     <filter>
    13      <filter-name>struts2</filter-name>
    14      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>      
    15      <init-param>
    16           <param-name>actionPackages</param-name>
    17           <param-value>com.mycompany.myapp.actions</param-value>
    18      </init-param>    
    19   </filter>
    20   
    21   <filter-mapping>
    22       <filter-name>struts2</filter-name>
    23        <url-pattern>/*</url-pattern>
    24   </filter-mapping>
    25   
    26   <!-- 自己的监听器配置 -->
    27   <listener>
    28       <listener-class>org.lister.Lis</listener-class>
    29   </listener>
    30   
    31 </web-app>
    1 package org.model;
    2 
    3 public class User {
    4     public void add(){
    5         System.out.println("add。。。。。。。。。。。。");
    6     }
    7 }
     1 package org.action;
     2 
     3 import java.util.Map;
     4 
     5 import javax.servlet.ServletContext;
     6 import org.apache.struts2.ServletActionContext;
     7 import org.model.User;
     8 import org.springframework.context.ApplicationContext;
     9 
    10 import com.opensymphony.xwork2.ActionContext;
    11 import com.opensymphony.xwork2.ActionSupport;
    12 
    13 public class UserAction extends ActionSupport {
    14     
    15     @Override
    16     public String execute() throws Exception {
    17         System.out.println("进入action");
    18 //        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
    19 //        User user=(User)ac.getBean("user");
    20 //        user.add();
    21         
    22         //得到ServletContext(上下文对象,即application对象)对象 并且得到里边保存的applicationContext对象;
    23         ServletContext servletContext = ServletActionContext.getServletContext(); 
    24         ApplicationContext ac=(ApplicationContext) servletContext.getAttribute("applicationcontext");
    25         if(ac!=null){
    26             User u=(User) ac.getBean("user");
    27             u.add();
    28         }
    29         
    30         /*
    31          //以下代码也能实现
    32         ActionContext actioncontext=ActionContext.getContext();
    33         Map application=actioncontext.getApplication();
    34         ApplicationContext ac2=(ApplicationContext) application.get("applicationcontext");
    35         if(ac2!=null){
    36             User u2=(User) ac2.getBean("user");
    37             u2.add();
    38         }
    39         */    
    40         return NONE;
    41     }
    42 }
    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <beans xmlns="http://www.springframework.org/schema/beans"
    3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4     xmlns:p="http://www.springframework.org/schema/p"
    5     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
    6         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    7         <bean id="user" class="org.model.User"></bean>
    8 </beans>

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

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

    然后访问action截图如下:

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

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

    1 package org.dao;
    2 
    3 public class UserDao {
    4     public void add(){
    5         System.out.println("UserDao.........");
    6     }
    7 }
     1 package org.service;
     2 
     3 import org.dao.UserDao;
     4 
     5 public class Service {
     6     private UserDao userdao;
     7     
     8     public void setUserdao(UserDao userdao) {//使用set注入
     9         this.userdao = userdao;
    10     }
    11     
    12     public void add(){
    13         System.out.println("Service.........");
    14         userdao.add();
    15     }
    16 }
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app version="2.5" 
     3     xmlns="http://java.sun.com/xml/ns/javaee" 
     4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     5     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
     6     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
     7   <welcome-file-list>
     8     <welcome-file>index.jsp</welcome-file>
     9   </welcome-file-list>
    10         <filter>
    11       <filter-name>struts2</filter-name>
    12       <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>      
    13       <init-param>
    14           <param-name>actionPackages</param-name>
    15           <param-value>com.mycompany.myapp.actions</param-value>
    16       </init-param>    
    17       </filter>
    18   <filter-mapping>
    19       <filter-name>struts2</filter-name>
    20       <url-pattern>/*</url-pattern>
    21   </filter-mapping>
    22   
    23   
    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>
    33 </web-app>
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans
     3     xmlns="http://www.springframework.org/schema/beans"
     4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     5     xmlns:p="http://www.springframework.org/schema/p"
     6     xmlns:aop="http://www.springframework.org/schema/aop"
     7     xsi:schemaLocation="http://www.springframework.org/schema/beans
     8     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     9     http://www.springframework.org/schema/aop 
    10     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    11     <bean id="ud" class="org.dao.UserDao"></bean>
    12     
    13     <bean id="us" class="org.service.Service">
    14         <property name="userdao" ref="ud"></property>
    15     </bean>
    16     
    17 </beans>
    18     
    
    
     1 package org.action;
     2 
     3 import java.util.Map;
     4 
     5 import javax.servlet.ServletContext;
     6 
     7 import org.apache.struts2.ServletActionContext;
     8 import org.springframework.context.ApplicationContext;
     9 import org.springframework.context.support.ClassPathXmlApplicationContext;
    10 import org.springframework.web.context.WebApplicationContext;
    11 import org.springframework.web.context.support.WebApplicationContextUtils;
    12 
    13 import com.opensymphony.xwork2.ActionSupport;
    14 
    15 import org.service.*;
    16 public class UserAction extends ActionSupport {
    17     
    18     @Override
    19     public String execute() throws Exception {
    20         //ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
    21         
    22         //得到servletContext对象(上下文application对象)
    23         ServletContext sc=ServletActionContext.getServletContext();    
    24         
    25         //从上下文对象中取得在服务器启动时创建的ApplicationContext对象
    26         //因为在服务器启动的时候就创建了一个applicationContext对象 并且保存在了ServletContext中(上下文application中),
    27         //并且键为:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
    28         ApplicationContext ac=(ApplicationContext)sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    29         if(ac!=null){
    30         Service s=(Service)ac.getBean("us");
    31         s.add();
    32         }else{
    33             System.out.println("没有取得ApplicationContext对象");
    34         }
    35         /*
    36         WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(ServletActionContext.getServletContext());  
    37         if(ac!=null){
    38         Service s=(Service)context.getBean("us");
    39         s.add(); 
    40         }else{
    41         System.out.println("没有取得ApplicationContext对象");
    42         }
    43          */
    44         return NONE;//不做任何的返回
    45     }
    46 }
    
    
    
    

    启动服务器:

     反复访问action:

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

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

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

    查看更多随笔:http://www.cnblogs.com/Joke-Jay/
  • 相关阅读:
    第五周读书笔记
    第五周课后作业(浅谈腾讯的创新)
    对象数组按属性排序
    id,pid数组转拓扑树结构
    ES6数组reduce()方法详解及高级技巧
    vue实现打印功能
    Js es6中扩展运算符(...)
    Axios 各种请求方式传递参数格式
    vue项目全局使用axios
    安装vue-cli脚手架
  • 原文地址:https://www.cnblogs.com/Joke-Jay/p/6507171.html
Copyright © 2020-2023  润新知