監聽器如何獲取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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM