博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
7 -- Spring的基本用法 -- 5... Spring容器中的Bean;容器中Bean的作用域;配置依赖;...
阅读量:6578 次
发布时间:2019-06-24

本文共 18691 字,大约阅读时间需要 62 分钟。

    7.5 Spring容器中的Bean

      7.5.1 Bean的基本定义和Bean别名

        <beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性:

          default-lazy-init : 指定该<beans.../> 元素下配置的所有Bean默认的延迟初始化行为。

          default-merge : 指定该<beans.../> 元素下配置的所有Bean默认的merge行为。

          default-autowire : 指定该<beans.../> 元素下配置的所有Bean 默认的自动装配行为。

          default-autowire-candidates: : 指定该<beans.../> 元素下配置的所有Bean 默认是否作为自动装配的候选Bean。

          default-init-method : 指定该<beans.../> 元素下配置的所有Bean 默认的初始化方法。

          default-destroy-method : 指定该<beans.../> 元素下配置的所有Bean 默认的回收方法。

        <beans.../>元素下所能指定的属性都可以在每个<bean.../>子元素中指定----将属性名去掉default即可。区别是:为<bean.../>指定的这些属性,只对特定Bean起作用;如果在<beans.../>元素下指定这些属性,这些属性将会对<beans.../>包含的所有Bean都起作用。当二者所指定的属性不一致时,<bean.../>下指定的属性会覆盖<beans.../>下指定的属性。

        <bean.../>元素的id属性具有唯一性,而且是一个真正的XML ID 属性,因此其他XML元素在引用id时,可以利用XML解析器的验证功能。

        指定别名有两种方式:

        ⊙ 定义<bean.../>元素时通过name属性指定别名;如果需要为Bean实例指定多个别名,则可以在name属性中使用逗号、冒号或者空格来分隔多个别名,后面通过任一别名即可访问该Bean实例。

        ⊙ 通过<alias.../>元素为已有的Bean指定别名。

          <alias name="" alias=""/> name:指定一个Bean实例的标识名,表明将为该Bean实例指定别名;alias:指定一个别名。

      7.5.2 容器中Bean的作用域

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

          ⊙ singleton : 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。

          ⊙ prototype : 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。

          ⊙ request : 对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。

          ⊙ session : 对于一次HTTP回话,session作用域的Bean将只生成一个实例,这意味着,在同一次HTTP回话内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。

          ⊙ global session : 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效。只有在Web应用中使用Spring时,该作用域才真正有效。

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

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

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

        Spring配置文件通过scope属性指定Bean的作用域。

        对于request作用域:

        针对每次HTTP请求,Spring容器会根据loginAction Bean定义创建一个全新的LoginAction Bean实例,且该loginAction Bean 实例仅在当前HTTP Request内有效。因此,如果程序需要,完全可以自由更改Bean实例的内部状态;其他请求所获得的loginAction Bean实例无法感受到这种内部状态的改变。当处理请求结束时,request作用域的Bean实例将被销毁。

        request、session作用域的Bean只对Web应用才真正有效。实际上通常只会将Web应用的控制器Bean指定成request作用域。

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

        对于支持Servlet2.4 及更新规范的Web容器,可以在Web应用的web.xml文件中增加如下Listener配置,该Listener负责是request作用域生效。

        Web : Listener

org.springframework.web.context.request.RequestContextListener

        对于只支持Servlet2.4 以前规范的Web容器,则该容器不支持Listener规范,故无法使用这种配置方式,只能改为使用Filter配置方式。

        Web :Filter

requestContextFilter
org.springframework.web.filter.RequestContextFilter
requestContextFilter
/*

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

        xml :app_7_5_2.xml

        如果Web应用直接使用Spring MVC作为MVC框架,即用SpringDispatcherServlet或DispatcherPorlet来拦截所有用户请求,则无须这些额外的配置,因为Spring DispatcherServlet和DispatcherPortlet已经处理了所有和请求有关的状态处理。

        Jsp :

<%    /* 获取Web应用初始化的Spring容器 */    WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext("app_7_5_2.xml");    /* 两次获取容器中id为per的Bean */    Person perA = (Person)ctx.getBean("per");    Person perB = (Person)ctx.getBean("per");    out.println((perA == perB) + "
"); out.println(perA); %>

      7.5.3 配置依赖

        Java 应用中各组件相互调用的实质可以归纳为依赖管理,根据注入方式的不同,Bean的依赖注入通常有如下两种形式。

          设置注入 : 通过<property.../>元素驱动Spring执行setter方法。

          构造注入 : 通过<constructor-arg.../>元素驱动Spring执行带参数的构造器。

        通常不建议使用配置文件管理Bean的基本类型的属性值;通常只使用配置文件管理容器中Bean与Bean之间的依赖关系。

        对于singleton作用域的Bean,如果没有强行取消其预初始化行为,系统会在创建Spring容器时预初始化所有的singleton Bean,与此同时,该Bean所以来的Bean也被一起实例化。

        BeanFactory 与 ApplicationContext 实例化容器中Bean的时机不同;BeanFactory等到程序需要Bean实例时才创建Bean;而ApplicationContext在容器创建ApplicationContext实例时,会预初始化容器中所有的singleton Bean。

        因为采用ApplicationContext作为Spring容器,创建容器时会同时创建容器中所有singleton作用域的Bean,因此可能需要更多的系统开销。但一旦创建成功,应用后面的响应速度更快,因此,对于普通的Java EE 应用,推荐使用ApplicationContext作为Spring容器。

        Spring的作用就是管理Java EE组件,Spring把所有的Java对象都称为Bean。因此完全可以把任何Java类都部署在Spring容器中----只要该Java类具有响应的构造器即可。Spring可以为任何Java对象注入任何类型的属性------只要该Java对象为该属性提供了对应的setter方法即可。

        Java 类的成员变量可以是各种数据类型,出了基本类型值、字符串类型值等,还可以是其他Java 实例,也可以是容器中的其他Bean实例,甚至是Java 集合、数组等,所以Spring允许通过如下元素为setter方法、构造器参数指定参数值:

        ⊙ value

        ⊙ ref

        ⊙ bean

        ⊙ list、set、map 及 props

      7.5.4 设置普通属性值------<value>

        <value.../>元素用于指定基本类型及其包装、字符串类型的参数值,Spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEditor完成类型转换:从java.lang.String类型转换为所需的参数值类型。

        Class : ExampleBean

package edu.pri.lime._7_5_4.bean;public class ExampleBean {//    定义一个int型的成员变量    private int integerField;//    定义一个double型的成员变量    private double doubleField;//    integerField和doubleField的setter和getter值    public int getIntegerField() {        return integerField;    }    public void setIntegerField(int integerField) {        this.integerField = integerField;    }    public double getDoubleField() {        return doubleField;    }    public void setDoubleField(double doubleField) {        this.doubleField = doubleField;    }    @Override    public String toString() {        return "ExampleBean [integerField=" + integerField + ", doubleField=" + doubleField + "]";    }}

        XML :

        Class : Test

package edu.pri.lime._7_5_4.main;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import edu.pri.lime._7_5_4.bean.ExampleBean;public class Test {    public static void main(String[] args) {        ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_4.xml");        ExampleBean exb = ctx.getBean("exampleBean",ExampleBean.class);        System.out.println(exb.toString());    }}

       7.5.5 配置合作者Bean------<ref.../>

        如果需要为Bean设置的属性值是容器中的另一个Bean实例,则应该使用<ref.../>元素。使用<ref.../>元素时可指定一个bean属性,该属性用于引用容器中其他Bean实例的id属性值。

        

   

        <contructor-arg.../>运算也可增加ref属性,从而指定将容器中另一个Bean作为构造器参数。

      7.5.6 使用自动装配注入合作者Bean------<beans default-autowire="" .../> 或 <bean autowire="" .../>

        Spring 能自动装配Bean与Bean之间的依赖关系,即无须使用ref显示指定依赖Bean,而是有Spring容器检查XML配置文件内容,根据某种规则,为调用者Bean注入被依赖的Bean。

        Spring 的自动装配可通过<beans.../>元素的default-autowire属性指定,该属性对配置文件中所有的Bean起作用;也可通过<bean.../>元素的autowire属性指定,该属性只对该Bean起作用。

        自动装配可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。

        default-autowire、autowire属性可以接受如下值:

        ⊙ no : 不使用自动装配。Bean依赖必须通过ref元素定义。这是默认配置,在较大的部署环境中不鼓励改变这个配置,显示配置合作者能够得到跟清晰的依赖关系。

        ⊙ byName : 根据setter方法名进行自动装配。Spring 容器查找容器中的全部Bean,找出其id与setter方法匹配的Bean作为参数来完成注入。如果没有找到匹配的Bean实例,则Spring不会进行任何注入。

        ⊙ byType : 根据setter方法的形参类型来自动装配。Spring容器查找容器中的全部Bean,如果正好有一个Bean类型与setter方法的形参类型匹配,就自动注入这个Bean;如果找到多个这样的Bean,就抛出一个异常;如果没有找到这样的Bean,则什么都不会发生,setter方法不会被调用。

        ⊙ constructor : 与byType类似,区别是用于自动匹配构造器的参数。如果容器不能恰好找到一个与构造器类型匹配的Bean,则会抛出一个异常。

        BUG ⊙ autodetect : Spring容器根据Bean内部结构,自行决定使用constructor或byType策略。如果找到一个默认的构造函数,那么就会应用byType策略。

        ⊙ default : 

        7.5.6.1 byName 规则

          byName 规则是指setter方法的方法名与Bean的id进行匹配,假如Bean A的实现类包含setB()方法,而Spring的配置文件恰好包含id为b的Bean,则Spring容器会将b实例注入Bean A中。如果容器中没有名字匹配的Bean,Spring则不会做任何事情。

        7.5.6.2 byType 规则

          byType 规则是根据setter方法的参数类型与Bean的类型进行匹配。假如A实例有setB(B b)方法,而Spring的配置文件中恰好有一个类型为B的Bean实例,容器为A注入类型匹配的Bean实例,如果容器中没有类型为B的实例,Spring不会调用setB()方法;但如果容器中包含多于一个的B实例,程序将会抛出异常。

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

          在某些情况下,程序希望将某些Bean排除在自动装配之外,不作为Spring自动装配策略的候选者,此时可设置autowire-candidate属性,通过为<bean.../>元素设置autowire-candidate=“false”,即可将Bean排除在自动装配之外,容器在查找自动装配Bean时将不考虑该Bean。

          还可通过在<beans.../>元素中指定default-autowire-candidates属性将一批Bean排除在自动装配之外。default-autowire-candidates属性的值允许使用模式字符串,例如指定default-autowire-candidates=“*abc”,则所有以“abc”结尾的Bean都将被排除在自动装配之外。不仅如此,该属性甚至可以指定多个模式字符串,这样所有匹配任意模式字符串的Bean都将被排除在自动装配之外。

      7.5.7 注入嵌套Bean

        如果某个Bean所依赖的Bean不想被Spring容器直接访问,则可以使用嵌套Bean。

        把<bean.../>配置成<property.../>或<constructor-args.../>的子元素,那么该<bean.../>元素配置的Bean仅仅作为setter注入、构造注入的参数,这种Bean就是嵌套Bean。由于容器布恩那个获取嵌套Bean,因此它不需要指定id属性。

        使用嵌套Bean与使用ref引用ref引用容器中另一个Bean在本质上是一样的。

        Spring框架的本质就是通过XML配置文件来驱动Java代码,当程序要调用setter方法或有参数的构造器时,程序总需要传入参数值,随参数类型的不同,Spring配置文件当然也要随之改变。

        ⊙ 形参类型是基本类型、String、日期等,直接使用value指定字面值即可。

        ⊙ 形参类型是复合类,那就需要传入一个Java队形作为实参,于是有两种方式:① 使用ref引用一个容器中已配置的Bean;② 使用<bean.../>元素配置一个嵌套Bean。

      7.5.8 注入集合值

        如果需要调用形参类型为集合的setter方法,或调用形参类型为集合的构造器,则可使用集合元素<list.../>、<set.../>、<map.../>和<props.../>分别来设置类型为List、Set、Map和Properties的集合参数值。

        Class : Chinese

package edu.pri.lime._7_5_8.bean.impl;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Set;import edu.pri.lime._7_5_8.bean.Axe;import edu.pri.lime._7_5_8.bean.Person;public class Chinese implements Person {//    集合类型的成员变量    private List
schools; private Map scores; private Map
phaseAxes; private Properties health; private Set axes; private String[] books; public Chinese() { super(); System.out.println("Spring 实例化主调bean:Chinese实例..."); } public List
getSchools() { return schools; } public void setSchools(List
schools) { this.schools = schools; } public Map getScores() { return scores; } public void setScores(Map scores) { this.scores = scores; } public Map
getPhaseAxes() { return phaseAxes; } public void setPhaseAxes(Map
phaseAxes) { this.phaseAxes = phaseAxes; } public Properties getHealth() { return health; } public void setHealth(Properties health) { this.health = health; } public Set getAxes() { return axes; } public void setAxes(Set axes) { this.axes = axes; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; }// 访问全部的集合类型的成员变量 public void test(){ System.out.println(schools); System.out.println(scores); System.out.println(phaseAxes); System.out.println(health); System.out.println(axes); System.out.println(Arrays.toString(books)); }}

        XML : 

小学
中学
大学
正常
175
普通的字符串
20
30
li
me
Oracle

        Spring对List集合和数组的处理是一样的,都用<list.../>元素来配置。

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

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

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

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

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

        <props.../>元素用于配置Properties类型的参数值,Properties类型是一种特殊的类型,其key和value都只能是字符串,故Spring配置Properties类型的参数值比较简单:每个key-value对只要分别给出key和value就足够了------而且key和value都是字符串类型,所以使用如下格式的<prop.../>元素就够了。

          ⊙ <prop key="key">value</prop> : 其中<prop.../>元素的key属性指定key的值,<prop.../>元素的内容指定value的值。

        当使用<map.../>元素配置Map参数值时,Map集合的每个元素由key、value两个部分组成,所以配置文件中的每个<entry.../>配置一组key-value对,其中<entry.../>元素支持如下4个属性:

            ⊙ key : 如果Map key是基本类型值或字符串,则可使用该属性来指定Map key。

            ⊙ key-ref : 如果Map key是容器中的另一个Bean实例,则可使用该属性指定容器中其他Bean的id。

            ⊙ value : 如果Map value 是节本类型值或字符串,则可使用该属性来指定Map value。

            ⊙ value-ref : 如果Map value 是容器中的另一个Bean实例,则可使用该属性指定容器中其他Bean的id。

        Spring 还提供了一个简化语法来支持Properties形参的setter方法:但这种配置语法中属性名、属性值都只能是英文、数字,不可出现中文。

pressure=normal height=175

        从Spring 2.0 开始,Spring IoC容器支持集合的合并,子Bean中集合属性值可以从其父Bean的集合属性继承和覆盖而来。即子Bean的集合属性的最终值是父Bean、子Bean合并后的最终结果,而且子Bean集合的元素可以覆盖父Bean集合中对应的元素。

administrator@crazyit.org
support@crazyit.org
sales@crazyit.org
master@crazyit.org

        由于泛型的支持,Java可以使用泛型指定集合元素的类型,Spring可通过反射来获取集合元素的类型,这样Spring的类型转换器就会起作用了。

        Class : Test

package edu.pri.lime._7_5_8.bean.impl;import java.util.Map;public class Test {// 程序使用了泛型限制了Map的key是String,value是double,Spring可根据泛型信息把配置文件的集合参数值转换成响应的数据类型    private Map
prices; public void setPrices(Map
prices) { this.prices = prices; } }

        XML : 

  

        Spring 会自动将每个entry中的key值转换成String类型,并将value指定的值转换成Double类型。

      7.5.9 组合属性

        Spring 还支持组合属性的方式。例如,使用配置文件为形如foo.bar.name的属性设置参数值。为Bean的组合属性设置参数值时,除最后一个属性之外,其他属性值都不允许为null。

        Class : ExampleBean

package edu.pri.lime._7_5_9.bean;public class ExampleBean {//    定义一个Person类型的成员变量。使用组合属性设置参数值时person不能为空    private Person person = new Person();    public Person getPerson() {        return person;    }    public void setPerson(Person person) {        this.person = person;    }    }

        Class : Person

package edu.pri.lime._7_5_9.bean;public class Person {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

        XML : 

        Class : TestBean

package edu.pri.lime._7_5_9.main;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import edu.pri.lime._7_5_9.bean.ExampleBean;public class TestBean {    public static void main(String[] args){        ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_9.xml");        ExampleBean exampleBean = ctx.getBean("exampleBean",ExampleBean.class);        System.out.println(exampleBean.getPerson().getName());    }}

      7.5.10 Spring的Bean和JavaBean

        Spring容器对Bean没有特殊要求,甚至不需要该Bean像标准的JavaBean------必须为每个属性提供对应的getter和setter方法。

        Spring中的Bean是Java实例、Java组件;传统Java应用中的JavaBean通常作为DTO(数据传输对象),用来封装值对象,在各层之间传递数据。

        传统的JavaBean也可作为Spring的Bean,从而接受Spring管理。

        eg:将数据源配置成容器中的Bean,该数据源Bean即可用于获取数据库连接。

        XML :

        Class : BeanTest

package edu.pri.lime._7_5_10.main;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import javax.sql.DataSource;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class BeanTest {    public static void main(String[] args) throws SQLException{        ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_10.xml");        DataSource ds = ctx.getBean("dataSource",DataSource.class);//        通过DataSource来获取数据库连接        Connection conn = ds.getConnection();//        通过数据库连接获取PerparedStatement        PreparedStatement pstmt = conn.prepareStatement("insert into news_inf value(null,?,?)");        pstmt.setString(1, "lime Cry");        pstmt.setString(1, "lime Happy");//        执行SQL语句        pstmt.executeUpdate();//        清理资源,回收数据库连接资源        if(pstmt != null){            pstmt.close();        }        if(conn != null){            conn.close();        }    }}

        虽然Spring对Bean没有特殊要求,但依然建议Spring中的Bean应满足如下几个原则:

          ⊙ 尽量为每个Bean实现类提供无参数的构造器。

          ⊙ 接受构造注入的Bean,则应提供对应的、带参数的构造器。

          ⊙ 接受设置注入的Bean,则应提供对应的setter方法,并不要求提供对应的getter方法。

        传统的JavaBean和Spring中的Bean之间的区别:

          ⊙ 用处不同 : 传统的JavaBean更多是作为值对象传递参数;Spring的Bean用处几乎无所不包,任何应用组件都被称为Bean。

          ⊙ 写法不同 : 传统的JavaBean作为值对象,要求每个属性都提供getter和setter方法;但Spring的Bean只需为接受设置注入的属性提供setter方法即可。

          ⊙ 生命周期不同 : 传统的javaBean作为值对象传递,不接受任何容器管理其生命周期;Spring中的Bean有Spring管理其声明周期行为。

转载地址:http://nmyno.baihongyu.com/

你可能感兴趣的文章
SDUST 2844-Mineral Water(数学)
查看>>
我的第一个开源控件-DragGridView
查看>>
5 Protocols For Event-Driven API Architectures
查看>>
Git篇
查看>>
Navicat for MySQL 使用SSH方式链接远程数据库(二)
查看>>
Linux常用基本命令( mkdir )
查看>>
JS原型 原型链
查看>>
maven打包时跳过测试
查看>>
Wix 安装部署教程(十) --来,用WPF做个漂亮的安装界面
查看>>
WPF 窗口居中 & 变更触发机制
查看>>
php标准库spl栈SplStack如何使用?
查看>>
机器学习新手使用入门
查看>>
详解Spring Boot集成MyBatis的开发流程
查看>>
C# Winform制作虚拟键盘,支持中文
查看>>
Data Visualization – Banking Case Study Example (Part 1-6)
查看>>
Linux下用信号量实现对共享内存的访问保护
查看>>
九度OJ 1177 查找 (模拟)
查看>>
★Kali信息收集~★6.Dmitry:汇总收集
查看>>
分享一下学习css,js心得
查看>>
机器学习
查看>>