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
