如何获取Spring配置⽂件(加载⽣成Spring容器)
Spring容器是⽣成Bean的⼯⼚,我们在做项⽬的时候,会⽤到去获取的配置⽂件,然后从中拿出我们需要的bean出来,⽐如做⽹站⾸页,假设商品的后台业务逻辑都做好了,我们需要创建⼀个,在项⽬启动时将⾸页的数据查询出来放到application⾥,即在⾥调⽤后台商品业务逻辑的⽅法,也就是说我们需要在⾥获取Spring中配置的相应的bean。先把创建出来:
1. 创建InitDataListener
创建⼀个InitDataListener继承ServletContextListener:
1//@Component //是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
2public class InitDataListener implements ServletContextListener {
3
4private ProductService productService = null;//productService中定义了跟商品相关的业务逻辑
5
6    @Override
7public void contextDestroyed(ServletContextEvent event) {
8
9    }
10
11    @Override
12public void contextInitialized(ServletContextEvent event) {
13
14    }
15
16 }
并在l中配置该:
如上,productService中定义了商品的⼀些业务逻辑,并且这个productService是交给Spring管理的,那么我们如何得到这个对象呢?⾸先肯定的⼀点是:我们不能⾃⼰new出来,因为new出来的话就跟Spring的IoC没有关系了……主要有三种⽅式可以实现,我们先⼀个个分析,最后⽐较优劣。
2. 直接加载l⽂件
这种⽅式⽐较简单粗暴,不是要加载配置⽂件么?那好,我加载就是了,如下:
1//@Component //是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
2public class InitDataListener implements ServletContextListener {
3
4
5private ProductService productService = null; //productService中定义了跟商品相关的业务逻辑
6
7    @Override
8public void contextDestroyed(ServletContextEvent event) {
9
10    }
11
12    @Override
13public void contextInitialized(ServletContextEvent event) {
14// 获取业务逻辑类productService查询商品信息
15        ApplicationContext context = new ClassPathXmlApplicationContext("l");
16        productService = (ProductService) Bean("productService");
17        System.out.println(productService); //输出看看拿到了没有
18
19//下⾯是具体productService相关操作……
20    }
21
22 }
这种⽅法完全没问题,思路很清晰,先加载配置⽂件l,然后获取bean,但是启动tomcat后,我们看看控制台输出的信息:
到这⾥应该发现这种⽅式的弊端了,加载了两次配置⽂件,也就是说那些bean被实例化了两次,从打印的信息来看,是拿到我们⾃⼰加载配置⽂件是实例化的bean。这种⽅式明显不可取。
3. 从ServletContext中获取
从上⾯的⽅法中,我们最起码可以知道,Spring通过⾃⼰的已经加载过⼀次配置⽂件了,我们没必要再加载⼀次,那么很容易想到,如果知道Spring加载后放到哪⾥了,那我们就可以从那地⽅获取该配置⽂件,下⾯我们看下Spring加载配置⽂件的过程:
上图中(省略了⽆关的代码),ContextLoaderListener就是l中我们配置的Spring,它也实现了ServletContextListener并继承了ContextLoader。在中主要通过initWebApplicationContext⽅法来获取配置⽂件,并创建WebApplicationContext对象,在initWebApplicationContext⽅法⾥主要做两件
事:⼀是拿到Spring的上下⽂,⼆是把Spring上下⽂放到ServletContext中,并且键为:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。那么如何拿到Spring的上下⽂呢?是通过获取l中配置的Spring的路径,CONFIG_LOCATION_PARM其实是个字符串常量,就是上⾯l中配置Spring下⾯的:
<context-param>
<param-name>contextConfigLocation</param-name> <!--CONFIG_LOCATION_PARM就是contextConfigLocation-->
<param-value>l</param-value>
</context-param>
  所以就很明显了,通过l中配置的路径拿到l,然后加载这个配置⽂件,实例化bean。
现在我们既然知道了Spring在加载配置⽂件后,把它放在了ServletContext中,那么我们就可以去这⾥⾯直接拿!
1//@Component //是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
2public class InitDataListener implements ServletContextListener {
3
4
5private ProductService productService = null;
6
7    @Override
8public void contextDestroyed(ServletContextEvent event) {
9// TODO Auto-generated method stub
10
11    }
13    @Override
14public void contextInitialized(ServletContextEvent event) {
15//  获取业务逻辑类查询商品信息
16
17// 解决⽅案⼆,项⽬在启动时,把Spring配置⽂件通过Spring的加载,存储到ServletContext中,我们只要在ServletContext中获取即可。
18        ApplicationContext context = (ApplicationContext) ServletContext()
19                                              .getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
20        productService = (ProductService) Bean("productService");
21        System.out.println(productService);
22    }
23
24 }
这样我们就可以拿到produceService的实例化对象了,这种⽅法好是好,就是getAttribute中的参数太长,也不知道当时程序员的脑门⼦被夹了还是咋地,估计是想不到其他更合适的名字了吧~
4. 通过Spring提供的⼯具类加载
也许开发Spring的⼤⽜们也意识到了这个参数名字太长了,于是他们提供了⼀个⽅法类,可以加载配置⽂件:
1public class InitDataListener implements ServletContextListener {
2
3
4private ProductService productService = null;
5
6    @Override
7public void contextDestroyed(ServletContextEvent event) {
8// TODO Auto-generated method stub
9
10    }
11
12    @Override
13public void contextInitialized(ServletContextEvent event) {
14// 获取业务逻辑类查询商品信息
15
16        WebApplicationContext context = ServletContext());
17        productService = (ProductService) Bean("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。
代码实践:
Spring整合web项⽬时的问题:
启动服务器之后:
访问action时,每次访问都会重新加载spring配置⽂件,效率低下
解决⽅法:在服务器启动的时候,利⽤只加载⼀次spring配置⽂件即可。
在spring⾥边不需要⾃⼰写代码实现,框架已经做好了封装
只需要配置即可:但是配置时,需要导⼊⼀个spring整合web项⽬的jar包
创建⼀个web项⽬,要求每次访问action都⽆需加载新的xml⽂件,利⽤框架的实现只在服务器启动时加载⼀次xml配置,⽤于提⾼性能
开发准备,导⼊struts相关jar和spring框架IOC相关jar以及spring整合web项⽬的jar包
第⼀种⾃⼰完成的代码(不推荐,纯属娱乐)
1package org.lister;
2
3import javax.servlet.ServletContext;
4import javax.servlet.ServletContextEvent;
5import javax.servlet.ServletContextListener;
6
7import t.ApplicationContext;
8import t.support.ClassPathXmlApplicationContext;
9
10public class Lis implements ServletContextListener {
11
12public void contextDestroyed(ServletContextEvent arg0) {
13// TODO Auto-generated method stub
14
15    }
16public void contextInitialized(ServletContextEvent arg0) {
17// TODO Auto-generated method stub
18//服务器启动的时候创建ApplicationContext对象
19        ApplicationContext ac=new ClassPathXmlApplicationContext("l");
20
21//得到ServletContext对象
22        ServletContext ServletContext();
23
24//保存创建的ApplicationContext对象,在action中调⽤
25        sc.setAttribute("applicationcontext",ac);
27 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app version="2.5"
3    xmlns="java.sun/xml/ns/javaee"
4    xmlns:xsi="/2001/XMLSchema-instance"
5    xsi:schemaLocation="java.sun/xml/ns/javaee
6    java.sun/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.filter.StrutsPrepareAndExecuteFilter</filter-class>
15      <init-param>
16          <param-name>actionPackages</param-name>
17          <param-value&app.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>
del;
2
3public class User {
4public void add(){
5        System.out.println("add。。。。。。。。。。。。");
6    }
7 }
1package org.action;
2
3import java.util.Map;
4
5import javax.servlet.ServletContext;
6import org.apache.struts2.ServletActionContext;
del.User;
8import t.ApplicationContext;
9
10import com.opensymphony.xwork2.ActionContext;
11import com.opensymphony.xwork2.ActionSupport;
12
13public class UserAction extends ActionSupport {
14
15    @Override
16public String execute() throws Exception {
17        System.out.println("进⼊action");
18//        ApplicationContext ac=new ClassPathXmlApplicationContext("l");
19//        User user=(Bean("user");
20//        user.add();
21
22//得到ServletContext(上下⽂对象,即application对象)对象并且得到⾥边保存的applicationContext对象;
23        ServletContext servletContext = ServletContext();
24        ApplicationContext ac=(ApplicationContext) Attribute("applicationcontext");
25if(ac!=null){
26            User u=(User) ac.getBean("user");
27            u.add();
28        }
29
30/*
31        //以下代码也能实现
32        ActionContext Context();
33        Map Application();
34        ApplicationContext ac2=(ApplicationContext) ("applicationcontext");
35        if(ac2!=null){
36            User u2=(User) Bean("user");
37            u2.add();
38        }
39*/
40return NONE;
41    }
42 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="/schema/beans"
3    xmlns:xsi="/2001/XMLSchema-instance"
4    xmlns:p="/schema/p"
5    xmlns:aop="/schema/aop" xsi:schemaLocation="
6        /schema/beans /schema/beans/spring-beans.xsd">
实例化bean的三种方式
7        <bean id="user" class="del.User"></bean>
8 </beans>
在上边的程序中没有配置spring框架的,只配置了⾃⼰定义的,所以也实现了题⽬要求的功能:
服务器启动的时候加载了配置⽂件:
然后访问action截图如下:
即使反复请求,只会输出以上两句,控制台并没有打印其他内容,说明xml⽂件只加载了⼀次。
第⼆种:使⽤框架提供的监听机制,我们只需要配置即可,不多说直接上代码
1package org.dao;
2
3public class UserDao {
4public void add(){
5        System.out.println(".");
6    }
7 }
1package org.service;
2
3import org.dao.UserDao;
4
5public class Service {
6private UserDao userdao;
7
8public void setUserdao(UserDao userdao) {//使⽤set注⼊
9this.userdao = userdao;
10    }
11
12public void add(){
13        System.out.println(".");
14        userdao.add();
15    }
16 }
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app version="2.5"
3    xmlns="java.sun/xml/ns/javaee"
4    xmlns:xsi="/2001/XMLSchema-instance"
5    xsi:schemaLocation="java.sun/xml/ns/javaee
6    java.sun/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.filter.StrutsPrepareAndExecuteFilter</filter-class>
13      <init-param>
14          <param-name>actionPackages</param-name>
15          <param-value&app.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.t.ContextLoaderListener</listener-class>
27  </listener>
28
29  <context-param>
30      <param-name>contextConfigLocation</param-name>
31      <param-value>l</param-value>
32  </context-param>
33</web-app>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans
3    xmlns="/schema/beans"
4    xmlns:xsi="/2001/XMLSchema-instance"
5    xmlns:p="/schema/p"
6    xmlns:aop="/schema/aop"
7    xsi:schemaLocation="/schema/beans
8    /schema/beans/spring-beans-3.0.xsd
9    /schema/aop
10    /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
1package org.action;
2
3import java.util.Map;
4
5import javax.servlet.ServletContext;
6
7import org.apache.struts2.ServletActionContext;
8import t.ApplicationContext;
9import t.support.ClassPathXmlApplicationContext;
10import org.t.WebApplicationContext;
11import org.t.support.WebApplicationContextUtils;
12
13import com.opensymphony.xwork2.ActionSupport;
14
15import org.service.*;
16public class UserAction extends ActionSupport {
17
18    @Override
19public String execute() throws Exception {
20//ApplicationContext ac=new ClassPathXmlApplicationContext("l");
21
22//得到servletContext对象(上下⽂application对象)
23        ServletContext ServletContext();
24
25//从上下⽂对象中取得在服务器启动时创建的ApplicationContext对象
26//因为在服务器启动的时候就创建了⼀个applicationContext对象并且保存在了ServletContext中(上下⽂application中),
27//并且键为:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
28        ApplicationContext ac=(Attribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); 29if(ac!=null){
30        Service s=(Bean("us");
31        s.add();
32        }else{
33            System.out.println("没有取得ApplicationContext对象");
34        }
35/*
36        WebApplicationContext context = ServletContext());
37        if(ac!=null){
38        Service s=(Bean("us");
39        s.add();
40        }else{
41        System.out.println("没有取得ApplicationContext对象");
42        }
43*/