zoukankan      html  css  js  c++  java
  • Spring Bean

    http://blog.csdn.net/chenssy/article/details/8222744

     从前面我们知道Spring其实就是一个大型的工厂,而Spring容器中的Bean就是该工厂的产品.对于Spring容器能够生产那些产品,则取决于配置文件中配置。

            对于我们而言,我们使用Spring框架所做的就是两件事:开发Bean、配置Bean。对于Spring矿建来说,它要做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法完成“依赖注入”。

     

            一、Bean的定义

            <beans…/>元素是Spring配置文件的根元素,<bean…/>元素师<beans../>元素的子元素,<beans…/>元素可以包含多个<bean…/>子元素,每个<bean…/>元素可以定义一个Bean实例,每一个Bean对应Spring容器里的一个Java实例定义Bean时通常需要指定两个属性。

             Id:确定该Bean的唯一标识符,容器对Bean管理、访问、以及该Bean的依赖关系,都通过该属性完成。Bean的id属性在Spring容器中是唯一的。    

            Class:指定该Bean的具体实现类。注意这里不能使接口。通常情况下,Spring会直接使用new关键字创建该Bean的实例,因此,这里必须提供Bean实现类的类名。

            下面是定义一个Bean的简单配置

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    3.     xmlns="http://www.springframework.org/schema/beans"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    5.     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    6.     <!-- 定义第一个Bean实例:bean1 -->  
    7.     <bean id="bean1" class="com.Bean1" />  
    8.       
    9.     <!-- 定义第二个Bean实例:bean2 -->  
    10.     <bean id="bean2" class="com.Bean2" />  
    11.       
    12. </bean>  

           

            Spring容器集中管理Bean的实例化,Bean实例可以通过BeanFactory的getBean(Stringbeanid)方法得到。BeanFactory是一个工厂,程序只需要获取BeanFactory引用,即可获得Spring容器管理全部实例的引用。程序不需要与具体实例的实现过程耦合。大部分Java EE应用里,应用在启动时,会自动创建Spring容器,组件之间直接以依赖注入的方式耦合,甚至无须主动访问Spring容器本身。

            当我们在配置文件中通过<bean id=”xxxx” class=”xx.XxClass”/>方法配置一个Bean时,这样就需要该Bean实现类中必须有一个无参构造器。故Spring底层相当于调用了如下代码:

    1. Xxx = new xx.XxClass()  


            如果在配置文件中通过构造注入来创建Bean:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    3.     xmlns="http://www.springframework.org/schema/beans"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    5.     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    6.     <bean id="bean1" class="com.Bean1">  
    7.         <constructor-arg value="chenssy"/>  
    8.         <constructor-arg value="35-354"/>  
    9.     </bean>  
    10.       
    11. </beans>  


            则Spring相当于调用如下代码:

    1. Bean bean = new com.Test("chenssy","35-354");  

            除了可以为<bean…/>元素指定一个id属性外,还可以为<bean…/>元素指定name属性,用于为Bean实例指定别名。如果需要为Bean实例指定多个别名,可以在name属性中使用逗号、冒号或者空格来分隔多个别名,后面通过任一别名即可访问该Bean实例。但是在一些特殊的情况下,程序无法在定义Bean时就指定所有的别名,而是在其他地方为一个已经存在的Bean实例指定别名,则可以使用<alias…/>元素来完成,该元素有如下两个属性:

            name:该属性指定一个Bean实例的标识名,表示将会为该Bean指定别名。

            alias:指定一个别名.

            如:

    1. <alias name=”bean1” alias=”name1”/>  
    2. <alias name=”bean2” alias=”name2”/>  

            在默认情况下,当Spring创建ApplicationContext容器时,Spring会自动预初始化容器中所有的singleton实例,如果我们想让Spring容器预初始化某个singleton Bean,则可以为该<bean…/>元素增加lazy-init属性,该属性用于指定该Bean实例的预初始化,如果设置为true,则Spring不会预初始化该Bean实例。

    1. <bean id=”person” class=”com.Person” lazy-init=”true”/>  

     

            一、       容器中Bean的作用域        当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。

            Spring支持5种作用域:

               Singleton:单例模式。在整个SpringIoC容器中,使用singleton定义的Bean将只有一个实例。

               Prototype:原型模式。每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。

               request:对于每次HTTP请求,使用request定义的Bean都将产生一个新的实例,即每次HTTP请求都会产生不同的Bean实例。当然只有在WEB应用中使用Spring时,该作用域才真正有效。

            session:对于每次HTTPSession,使用session定义的Bean都将产生一个新的实例时,即每次HTTP Session都将产生不同的Bean实例。同HTTP一样,只有在WEB应用才会有效。

            global session:每个全局的HTTPSession对应一个Bean实例。仅在portlet Context的时候才有效。

           

            比较常用的singleton和prototype。如果一个Bean实例被设置为singleton,那么每次请求该Bean时都会获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为。如果一个Bean实例被设置为prototype,那么每次请求该di的Bean,Spring都会创建一个新的Bean实例返回给程序,在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,一旦创建成功,容器将不会再跟踪实例,也不会维护Bean实例的状态。

            如果我们不指定Bean的作用域,则Spring会默认使用singleton作用域。

            Java在创建Java实例时,需要进行内存申请。销毁实例时,需要完成垃圾回收。这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价会比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean的作用域设置为prototype。

            设置Bean的作用域是通过scope属性来指定。可以接受Singleton、prototype、request、session、global session 5个值。

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    3.     xmlns="http://www.springframework.org/schema/beans"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    5.     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    6.     <!-- 配置一个singleton Bean实例:默认 -->  
    7.     <bean id="bean1" class="com.Bean1" />  
    8.     <!-- 配置一个prototype Bean实例 -->  
    9.     <bean id="bean2" class="com.Bean2" scope="prototype"/>  
    10.       
    11. </beans>  

            上面的配置,对于bean1没有指定scope属性,则默认使用singleton,而bean2则指定一个prototype。

            测试代码:

    1. public class SpringTest {  
    2.   
    3.     public static void main(String[] args) {  
    4.         ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");  
    5.         //判断两次请求singleton作用域的Bean实例是否相等  
    6.         System.out.println(ctx.getBean("bean1")==ctx.getBean("bean1"));  
    7.         //判断两次请求prototype作用域的Bean实例是否相等  
    8.         System.out.println(ctx.getBean("bean2")==ctx.getBean("bean2"));  
    9.     }  
    10.   
    11. }  

            程序运行结果如下

         true

         false

            从上面的运行结果可以看出:对于singleton作用域的Bean,每次请求该id的Bean时都将返回同一个Bean实例,但是prototype返回的都是一个新的Bean实例,每次请求返回的Bean实例都将不同。

            对于request作用域而言,先看如下Bean实例定义:

    1. <bean id=”login” class=”com.app.LoginAction” scope=”request”/>  

            对于每次HTTP请求,Spring容器都会根据login Bean定义创建一个全新的LoginAction Bean实例,且该loginAction Bean实例仅在当前HTTP Request内有效。

            对于session作用域相同。只不过有效范围不同而已。

            request和session作用域只在web应用中才会有效,并且必须在Web应用中增加额外配置才会生效。为了能够让request和session两个作用域生效,必须将HTTP请求对象绑定到位该请求提供的服务线程上,这使得具有request和session作用的Bean实例能够在后面的调用链中被访问到。

            因此我们可以采用两种配置方式:采用Listener配置或者采用Filter配置,在web.xml中。

            Listener配置:

    1. <listener>  
    2.     <listener-class>  
    3.         org.springframework.web.context.request.RequestContextListener  
    4.     </listener-class>  
    5. </listener>  

            Filter配置

    1. <filter>  
    2.     <filter-name>requestContextFilter</filter-name>  
    3.     <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.     <filter-name>requestContextFilter</filter-name>  
    7.     <url-pattern>/*</url-pattern>  
    8. </filter-mapping>  

     

            一旦在web.xml中增加上面两种配置中的一种,程序就可以在Spring配置文件中使用request或者session作用域了。如下:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    3.     xmlns="http://www.springframework.org/schema/beans"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    5.     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    6.     <!-- 指定使用request作用域 -->  
    7.     <bean id="p" class="com.app.Person" scope="request"/>  
    8.       
    9. </beans>  

            上面的配置文件配置了一个实现类Person的Bean,指定它的作用域为request。这样Spring容器会为每次的HttP请求生成一个Person的实例,当该请求响应结束时,该实例也会被注销。

     

        读李刚《轻量级Java EE企业应用实战》

     

     

         Java实例的属性值可以有很多种数据类型、基本类型值、字符串类型、java实例甚至其他的Bean实例、java集合、数组等。所以Spring允许通过如下几个元素为Bean实例的属性指定值:

              value

              ref

              bean

              list、set、map、props

              一、value:设置普通属性值

              <value.../>元素用于指定字符串类型、基本类型的属性值。Spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEdior完成类型转换:从java.lang.String类型转换为所需的参数值类型。如果目标类型是基本数据类型,通常都是可以正确转换。

    复制代码
     1 public class ValueTest {
     2     //定义一个String型属性
     3     private String name;
     4     //定义一个int型属性
     5     private int age;
     6     
     7     public String getName() {
     8         return name;
     9     }
    10     public void setName(String name) {
    11         this.name = name;
    12     }
    13     
    14     public int getAge() {
    15         return age;
    16     }
    17     public void setAge(int age) {
    18         this.age = age;
    19     }
    20 }
    复制代码

              上面实例只是演示了注入普通属性值。在Spring配置文件中使用<value.../>元素来为这两个属性指定属性值。

    1 <bean id="text" class="com.spring.service.impl.ValueTest">
    2         <property name="age" value="1" />
    3         <property name="name" value="chenssy" />
    4     </bean>

              通过上面可以知道<value.../>元素主要用于传入字符串、基本类型的属性值。

              二、ref:配置合作者

              <value.../>主要是配置基本类型的属性值,但是如果我们需要为Bean设置属性值是另一个Bean实例时,这个时候需要使用<ref.../>元素。使用<ref.../>元素可以指定如下两个属性。

              bean:引用不在同一份XML配置文件中的其他Bean实例的id属性值。

              local:引用同一份XML配置文件中的其他Bean实例的id属性值。

    复制代码
    1 <bean id="steelAxe" class="com.spring.service.impl.SteelAce"></bean>
    2     <bean id="chinese" class="com.spring.service.impl.Chinese" >
    3         <property name="axe">
    4             <ref local="steelAxe"/>
    5         </property>
    6     </bean>
    复制代码

              其实Spring提供了一种更加简洁的写法:

    1 <bean id="steelAxe" class="com.spring.service.impl.SteelAce"></bean>
    2     <bean id="chinese" class="com.spring.service.impl.Chinese" >
    3         <property name="axe" ref="steelAxe" />
    4     </bean>

              通过property增加ref属性,一样可以将另一个Bean的引用设置成axe属性值。这样写的效果和使用<ref.../>属性一样,而且不需要区分是使用bean属性还是local属性,所以推荐这种写法。

              2.1、使用自动装配注入合作者bean

              Spring支持自动装配Bean与Bean之间的依赖关系,也就是说我们无需显示的指定依赖Bean。由BeanFactory检查XML配置文件内容,根据某种规则,为主调Bean注入依赖关系。

    Spring的自动装配机制可以通过<bean.../>元素的default-autowire属性指定,也可以通过<bean.../>元素的autowire属性指定。

              自动装配可以减少配置文件的工作量,但是它降低了依赖关系的透明性和清晰性,所以一般来说在较大部署环境中不推荐使用,显示配置合作者能够得到更加清晰的依赖关系。Spring提供了如下几种规则来实现自动装配。

              no:不适用自动装配。Bean依赖必须通过ref元素定义。

              byName:根据属性名自动装配。BeanFactory查找容器中的全部Bean,找出其中id属性与属性同名的Bean来完成注入。如果没有找到匹配的Bean实例,则Spring不会进行任何注入。

              byType:根据属性类型自动装配。BeanFactory查找容器中的全部Bean,如果正好有一个与依赖属性类型相同的Bean,就自动注入这个属性;但是如果有多个这样的Bean,就会抛出一个异常。如果没有匹配的Bean,则什么都不会发生,属性就不会被设置。如果需要无法自动装配时抛出异常,则设置dependency-check=”objects”。

              constructor:与不Type类似,区别是用于构造注入的参数。

              Autodetect:BeanFactory根据Bean内部结构,决定使用constructor或者byType。如果找到一个默认的构造函数,则使用byTe。

               

              byName规则

              byTyep规则是指通过名字注入依赖关系,假如Bean A的实现类里面包含setB()方法,而Spring的配置文件恰好包含一个id为b的Bean,则Spring容器就会将b实例注入Bean A中。如果容器中没有名字匹配的Bean,Spring则不会做任何事情。

    1 <bean id="chinese" class="com.spring.service.impl.Chinese" autowire="byName" />
    2     <bean id="gundog" class="com.spring.service.impl.Gundog">
    3         <property name="name" value="wangwang" />
    4     </bean>

              上面的配置文件指定了byName规则。则com.app.service.impl.Chinese类中提供如下的依赖注入方法:

    复制代码
    1 /*
    2      * 依赖关系必须的setter方法,因为需要通过名字自动装配
    3      * 所以setter方法必须提供set+Bean名,Bean名的首字母大写
    4      * @param dog 设置的dog值
    5      */
    6     public void setGundog(Dog dog){
    7         this.dog = dog;
    8     }
    复制代码

              byType规则

              byType规则是根据类型匹配注入依赖关系。假如A实例有setB(B b)方法,而Spring配置文件中恰好有一个类型B的Bean实例,容器为A注入类型匹配的Bean实例。如果容器中存在多个B的实例,则会抛出异常,如果没有B实例,则不会发生任何事情。

    1 <bean id="chinese" class="com.spring.service.impl.Chinese" autowire="byType" />
    2     <bean id="gundog" class="com.spring.service.impl.Gundog">
    3         <property name="name" value="wangwang" />
    4     </bean>

              针对上面的配置文件Chinese类有如下方法。

    复制代码
    1 /**
    2      * 依赖关系必须的setter方法
    3      * 因为使用按类型自动装配,setter方法的参数类型与容器的Bean的类型相同
    4      * 程序中的Gundog实现了Dog接口
    5      * @param dog传入的dog对象
    6      */
    7     public void setDog(Dog dog){
    8         this.dog = dog;
    9     }
    复制代码

              当一个Bean即使用自动装配依赖,又使用ref显示依赖时,则显示指定的依赖就会覆盖自动装配。

              在默认的情况下,Spring会自动搜索容器中的全部Bean,并对这些Bean进行判断,判断他们是否满足自动装配的条件,如果满足就会将该Bean注入目标Bean实例中。如果我们不想让Spring搜索容器中的全部Bean,也就是说,我们需要Spring来判断哪些Bean需要搜索,哪些Bean不需要搜索,这个时候就需要用到autowire-candidate属性。通过为<bean.../>元素设置autowire-candidate=”false”,即可将该Bean限制在自动装配范围之外,容器在查找自动装配对象时将不考虑该Bean。

              三、Bean:注入嵌套Bean

              如果某个Bean所依赖的Bean不想被Spring容器直接访问,则可以使用嵌套Bean。<bean.../>元素用来定义嵌套Bean,嵌套Bean只对嵌套它的外部Bean有效,Spring容器无法直接访问嵌套Bean,因此在定义嵌套Bean时是无需指定id属性的。

    复制代码
    1 <bean id="chinese" class="com.spring.service.impl.Chinese" autowire="byName">
    2         <property name="axe">
    3             <!-- 
    4                 属性值为嵌套Bean,嵌套Bean不能由Spring容器直接访问,
    5                 所以嵌套Bean是不需要id属性
    6              -->
    7             <bean class="com.spring.service.impl.SteelAce" />
    8         </property>
    9     </bean>
    复制代码

              采用上面的配置可以保证嵌套Bean不能被容器访问,因此不用担心其他程序修改嵌套bean。但是嵌套Bean限制了Bean的访问,提高了程序的内聚性。

              四、list、set、map、props

              <value.../>元素是注入基本数据类型和String类型的,但是如果某个Bean的属性是集合呢?这个时候我们就需要使用集合元素,<list.../>、<set.../>、<map.../>和<props.../>元素分别用来设置类型list、set、map和Properties的集合属性值。

              先看下面java类:

    复制代码
     1 public class Chinese implements Person{
     2 
     3     //下面是一系列的集合属性
     4     private List<String> schools;
     5     private Map scores;
     6     private Map<String, Axe> phaseAxes;
     7     private Properties health;
     8     private Set axe;
     9     private String[] books;
    10     
    11     public List<String> getSchools() {
    12         return schools;
    13     }
    14 
    15     public void setSchools(List<String> schools) {
    16         this.schools = schools;
    17     }
    18 
    19     public Map getScores() {
    20         return scores;
    21     }
    22 
    23     public void setScores(Map scores) {
    24         this.scores = scores;
    25     }
    26 
    27     public Map<String, String> getPhaseAxes() {
    28         return phaseAxes;
    29     }
    30 
    31     public void setPhaseAxes(Map<String, String> phaseAxes) {
    32         this.phaseAxes = phaseAxes;
    33     }
    34 
    35     public Properties getHealth() {
    36         return health;
    37     }
    38 
    39     public void setHealth(Properties health) {
    40         this.health = health;
    41     }
    42 
    43     public Set getAxe() {
    44         return axe;
    45     }
    46 
    47     public void setAxe(Set axe) {
    48         this.axe = axe;
    49     }
    50 
    51     public String[] getBooks() {
    52         return books;
    53     }
    54 
    55     public void setBooks(String[] books) {
    56         this.books = books;
    57     }
    58 
    59     public void useAxe() {
    60         
    61     }
    62 
    63 }
    复制代码

               上面的java代码中有数组、list、set、,map、Properties。下面是针对上面的配置文件。

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xmlns="http://www.springframework.org/schema/beans"
     4     xsi:schemaLocation="http://www.springframework.org/schema/beans
     5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     6     <!-- 定义一个普通的Axe Bean -->
     7     <bean id="steelAxe" class="com.spring.service.impl.SteelAxe" />
     8     <bean id="stoneAxe" class="com.spring.service.impl.StoneAxe" />
     9     
    10     <!--定义Chinese Bean -->
    11     <bean id="chinese" class="com.spring.service.impl.Chinese">
    12         <property name="schools">
    13             <list>
    14                 <value>小学</value>
    15                 <value>中学</value>
    16                 <value>大学</value>
    17             </list>
    18         </property>
    19         
    20         <property name="scores">
    21             <map>
    22                 <entry key="语文" value="88" />
    23                 <entry key="数学" value="87" />
    24                 <entry key="外语" value="88" />
    25             </map>
    26         </property>
    27         
    28         <property name="phaseAxes">
    29             <map>
    30                 <entry key="原始社会" value-ref="stoneAxe" />
    31                 <entry key="农业社会" value-ref="steelAxe" />
    32             </map>
    33         </property>
    34         
    35         <property name="health">
    36             <props>
    37                 <prop key="血压">正常</prop>
    38                 <prop key="身高">175</prop>
    39             </props>
    40         </property>
    41         
    42         <property name="axe">
    43             <set>
    44                 <value>普通字符串</value>
    45                 <bean class="com.spring.service.impl.SteelAxe"></bean>
    46                 <ref local="stoneAxe"/>
    47             </set>
    48         </property>
    49         
    50         <property name="books">
    51             <list>
    52                 <value>java 编程思想</value>
    53                 <value>思考致富</value>
    54                 <value>将才</value>
    55             </list>
    56         </property>
    57     </bean>
    58 </beans>
    复制代码

              从上面的配置文件中可以看出,Spring对list属性和数组属性的处理是一样的。

    当我们使用<list.../>、<set.../>、<map.../>等元素配置集合属性时,我们还需要手动配置集合元素。由于集合元素又可以是基本类型值、引用容器中的其他Bean、嵌套Bean和集合属性等。所以这些元素又可以接受如下子元素:

              value:指定集合元素是基本数据类型或者字符类型值。

              ref:指定集合元素师容器中另一个Bean实例。

              bean:指定集合元素是一个嵌套Bean。

              list、set、map、props:指定集合元素值又是集合。

  • 相关阅读:
    MySQL-基本sql命令
    Java for LeetCode 203 Remove Linked List Elements
    Java for LeetCode 202 Happy Number
    Java for LeetCode 201 Bitwise AND of Numbers Range
    Java for LeetCode 200 Number of Islands
    Java for LeetCode 199 Binary Tree Right Side View
    Java for LeetCode 198 House Robber
    Java for LeetCode 191 Number of 1 Bits
    Java for LeetCode 190 Reverse Bits
    Java for LeetCode 189 Rotate Array
  • 原文地址:https://www.cnblogs.com/diegodu/p/5948296.html
Copyright © 2011-2022 走看看