• Spring二 Bean详解


    Bean详解

    Spring框架的本质其实是:通过XML配置来驱动Java代码,这样就可以把原本由java代码管理的耦合关系,提取到XML配置文件中管理。这样就实现了系统中各组件的解耦,有利于后期的升级和维护。
    1.Bean的基本定义和Bean别名
    <beans>元素是Spring配置文件的根元素,该元素可以指定如下属性:
    default-lazy-init:指定<beans>元素下配置的所有bean默认的延迟初始化行为
    default-merge:指定<beans>元素下配置的所有bean默认的merge行为
    default-autowire:指定<beans>元素下配置的所有bean默认的自动装配行为
    default-init-method:指定<beans>元素下配置的所有bean默认的初始化方法
    default-destroy-method:指定<beans>元素下配置的所有bean默认的回收方法
    default-autowire-candidates:指定<beans>元素下配置的所有bean默认是否作为自动装配的候选Bean
    <beans>元素下所指定的属性都可以在每个<bean>子元素中指定,只要将属性名去掉default即可,这样就可以对特定bean起作用。
    定义Bean时,通常要指定两个属性:
    id:确定该Bean的唯一标识,Bean的id属性在Spring容器中应该是唯一的。
    class:指定该Bean的具体实现类,这里不能是接口,因为在通常情况下,Spring会直接使用new关键字创建该bean的实例。
    2.Bean的作用域
    Spring支持5种作用域:
    singleton:单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
    prototype:每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
    request、session:对于一次HTTP请求,request/session作用域的Bean将只产生一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring,该作用域才真正有效。
    global session:每个全局的HTTP Session对应一个Bean实例,在典型的情况下,仅在使用portlet context的时候有效。只有在Web应用中使用Spring,该作用域才真正有效。
    注意:如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回程序。在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,一旦创建成功,容器就不会再跟踪实例,也不会去维护bean实例的状态。
    Java在创建Java实例时,需要进行内存申请,销毁实例时,要进行垃圾回收,这些工作会增加系统开销。因此,使用prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,就可以重复使用。
    例如:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
    http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    //创建一个singleton Bean实例
    <bean id="p1" class="mySpring.Person" />
    //创建一个prototype Bean实例
    <bean id="p2" class="mySpring.Person" scope="prototype"/>
    <bean id="date" class="java.util.Date" />
    </beans>


    测试:

    public class myTest {
    public static void main(String[] args) {
    ApplicationContext ctx=new ClassPathXmlApplicationContext("a/ApplicationContext.xml");
    System.out.println(ctx.getBean("p1")==ctx.getBean("p1"));
    System.out.println(ctx.getBean("p2")==ctx.getBean("p2"));
    System.out.println(ctx.getBean("date"));
    Thread.sleep(1000);
    System.out.println(ctx.getBean("date"));
    }
    }

    结果是: true false Sun May 11 14:39:03 CST 2014 Sun May Sun May 11 14:39:03 CST 2014
    request和session作用域只在Web应用中有效,并且要在Web应用中增加额外配置才会生效,因此必须要将HTTP请求对象绑定到为该请求提供服务的线程上,这样才能使得具有request和session作用域的Bean实例能够在后面的调用链中被访问到。对于支持Servlet2.4及更新规范的Web容器,可以在Web应用的web.xml文件中添加如下的Listener配置:
    在WEB-INFweb.xml文件中:
    <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    JSP脚本:
    <body>
    <%
    WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(application);
    Perosn p1=(Perosn)ctx.getBean("perosn");
    Perosn p2=(Perosn)ctx.getBean("perosn");
    out.println((p1==p2)+"<br />");
    out.println(p1);
    %>
    </body>
    结果:刷新页面依旧输出true,但是两次的Perosn Bean不一样。
    3.配置依赖
    不管是设值注入,还是构造注入,都视为Bean依赖,接受Spring容器管理,依赖关系的值要么是一个确定的值,要么是Spring容器中其他Bean的引用。通常不建议使用配置文件管理Bean的基本类型的属性值,通常只使用配置文件管理容器中Bean与Bean之间的依赖关系。
    创建BeanFactory时不会立即创建Bean实例,所以有可能程序可以正确创建BeanFactory实例,但当请求Bean实例时依然抛出一个异常,创建Bean实例或注入它的依赖关系时出现错误。配置错误的延迟出现,也会给系统带来不安全因素。ApplicationContext实例化过程的时间和内存开销大,但可以在容器初始化阶段就检验出配置错误。
    Java类的成员变量可以是各种可以是各种数据类型,除了基本类型值、字符串类型值等,还可以是其他Java实例,也可以是容器中的其他Bean实例,甚至是Java集合、数组等,所以Spring允许通过如下元素为setter方法、构造器参数指定参数值:value,ref,bean,list,set,map及props。
    (1)设置普通属性值
    <value/>元素用于指定基本类型及其包装、字符串类型的参数值,Spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEditor完成类型转换:从java.lang.String类型转换为所需的参数值类型。如果目标类型是基本类型及其包装类,通常可以正确转换。
    如:
    <bean id="exampleBean" class="mySpring.ExampleBean">
    //指定int型的参数值
    <property name="field1" value="1" />
    //指定double型的参数值
    <property name="field2" value="2.3" />
    </bean>
    (2)配置合作者Bean
    如果需要为Bean设置的属性值是容器中的另一个Bean实例,则要用<ref />元素。使用<ref/>元素时可指定一个bean属性,该属性用于引用容器中其他Bean实例的id属性值。
    如:
    Person.java

    public class Person {
    private String name;
    private int age;
    private Car car;
    @Override
    public String toString() {
    return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    this.age = age;
    }
    public Car getCar() {
    return car;
    }
    public void setCar(Car car) {
    this.car = car;
    }
    public Person(String name, int age, Car car) {
    super();
    this.name = name;
    this.age = age;
    this.car = car;
    }
    public Person() {
    super();
    }
    }

    Car.java

    public class Car {    
    private String brand;
    private String corp;
    private double price;
    private int maxSpeed;
    public Car(String brand, String corp, double price) {
    super();
    this.brand = brand;
    this.corp = corp;
    this.price = price;
    }
    @Override
    public String toString() {
    return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price
    + ", maxSpeed=" + maxSpeed + "]";
    }
    }

    ApplicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="car" class="a.Car">
    <constructor-arg value="BaoMa" type="java.lang.String"></constructor-arg>
    <constructor-arg value="ShangHai" type="java.lang.String"></constructor-arg>
    <constructor-arg value="240" type="int"></constructor-arg>
    </bean>
    <bean id="person" class="a.Person">
    <property name="name" value="Tom"></property>
    <property name="age" value="20"></property>
    <property name="car" ref="car"></property> //也可以写为<property name="car"><ref bean="car" /></property>
    </bean>
    </beans>

    测试:

    public class myTest {
    public static void main(String[] args) {
    ApplicationContext ctx=new ClassPathXmlApplicationContext("a/ApplicationContext.xml");
    Person person=ctx.getBean(Person.class);
    System.out.println(person);
    }
    }

    结果:Person [name=Tom, age=20, car=Car [brand=BaoMa, corp=ShangHai, price=0.0, maxSpeed=240]]
    (3)使用自动装配注入合作者Bean
    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方法名去掉set前缀,并小写首字母后同名的Bean来完成注入。如果没有找到匹配的Bean,则不注入。
    byType:根据setter方法的形参类型来自动装配。Spring容器查找容器中的全部Bean,如果正好有一个Bean类型与setter方法的形参类型匹配,就自动注入这个Bean;如果找到多个,就抛出一个异常;如果没找到,就什么也不会发生。
    具体使用:
    byName规则
    <bean id="chinese" class="mySpring.Chinese" autowire="byName" />
    <bean id="gunDog" class="mySpring.GunDog">
    <property name="name" value="wangwang" />
    </bean>
    在Chinese类中一定会有如下setter方法:
    public void setGunDog(Dog dog){
    this.dog=dog;
    }
    Spring容器会寻找id为gunDog的Bean,如果能找到,该Bean就会作为调用setGunDog()方法的参数。
    byType规则
    <bean id="chinese" class="mySpring.Chinese" autowire="byType" />
    <bean id="gunDog" class="mySpring.GunDog">
    <property name="name" value="wangwang" />
    </bean>
    在Chinese类中一定会有如下setter方法:
    public void setGunDog(Dog dog){
    this.dog=dog;
    }
    上面setter方法的形参类型是Dog,而mySpring.GunDog Bean类实现了Dog接口,但是如果还有一个类同时也实现了Dog接口的话,如下:
    <bean id="gunDog" class="mySpring.PetDog">
    <property name="name" value="ohoh" />
    </bean>
    由于容器中有两个类型为Dog的Bean,Spring无法确定应为chinese Bean注入哪个Bean,则程序会抛出异常。
    当一个Bean既使用自动装配依赖,又使用ref显式指定依赖时,则显示指定的依赖会覆盖掉自动装配依赖。
    (4)注入嵌套Bean
    如果某个Bean所依赖的Bean不想被Spring容器直接访问,则可以使用嵌套Bean。这样的Bean称为内部Bean,不能被外部Bean引用,只能在内部使用,这里的bean不用id。
    <bean id="person" class="a.Person">
    <property name="name" value="Tom"></property>
    <property name="age" value="20"></property>
    <property name="car">
    <bean class="a.Car">
    <constructor-arg value="Ford"></constructor-arg>
    <constructor-arg value="Changan"></constructor-arg>
    <constructor-arg value="200000"></constructor-arg>
    </bean>
    </property>
    </bean>
    当形参类型是基本类型、String、日期等,直接使用value指定字面值即可;但形参类型是复合类(如Person、DataSource等),那就需要传入一个Java对象作为实参,主要有两种方法:使用ref引用一个容器中已经配置的Bean,或者使用<bean>元素配置一个嵌套Bean;形参类型是Set、List、Map等集合或者是数组类型时,要进行如下配置。
    (5)注入集合值
    集合元素<list>,<set>,<map>,<props>的具体设置
    Address.java

    public class Address{
    private String city;
    private String street;
    ...//此处省略getter/setter方法及其他方法
    }

    Car.java

    public class Car {    
    private String brand;
    private String corp;
    private double price;
    ...//此处省略getter/setter方法及其他方法
    }

    Person.java

    public class Person {
        private List<Car> cars;
        private List<String> schools;
        private Map scores;
        private Map<String,Car> cars1;
        private Properties health;
        private String[] books;
        ...//此处省略getter/setter方法及其他方法
    }

    ApplicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="car1" class="SpringTest.Car">
        <property name="brand" value="Ford"></property>
        <property name="corp" value="Changan"></property>
        <property name="price" value="200000"></property>
        </bean>
        
        <bean id="car2" class="SpringTest.Car">
        <property name="brand" value="BaoMa"></property>
        <property name="corp" value="ShangHai"></property>
        <property name="price" value="240000"></property>
        </bean>
        
        <bean id="person" class="SpringTest.Person">
        <property name="cars">
                <list>
                    <ref bean="car1"></ref>
                    <ref bean="car2"></ref>
                </list>
            </property>
            
        <property name="schools">
            <list>
                <value>小学</value>
                <value>中学</value>
                <value>大学</value>
            </list>
        </property>
        
        <property name="scores">
            <map>
                <entry key="数学" value="90" />
                <entry key="语文" value="90" />
                <entry key="英语" value="90" />
            </map>
        </property>
        
        <property name="cars1">
                <map>
                    <entry key="AA" value-ref="car1"></entry>
                    <entry key="BB" value-ref="car2"></entry>
                </map>
            </property>
            
        <property name="health">
            <props>
                <prop key="血压">正常</prop>
                <prop key="身高">175</prop>
            </props>
        </property>
        
        <property name="books">
            <list>
                <value>java学习</value>
                <value>javascript学习</value>
                <value>javaEE学习</value>
            </list>
        </property>
        </bean>
    </beans>

    测试:

    public class MainTest {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("SpringTest/ApplicationContext.xml");        
            Person p=(Person)ctx.getBean("person");
            System.out.println(p);
            ctx.close();
        }
    }

    结果:
    Person [cars=[Car [brand=Ford, corp=Changan, price=200000.0], Car [brand=BaoMa, corp=ShangHai, price=240000.0]], schools=[小学, 中学, 大学], scores={数学=90, 语文=90, 英语=90}, cars1={AA=Car [brand=Ford, corp=Changan, price=200000.0], BB=Car [brand=BaoMa, corp=ShangHai, price=240000.0]}, health={血压=正常, 身高=175}, books=[java学习, javascript学习, javaEE学习]]

  • 相关阅读:
    androidactivity与webview结合
    anroid打包
    android之Fragment
    android布局
    anroid
    map reduce filter
    杂记
    spark记录
    Tomact和XML配置文件
    js-day02
  • 原文地址:https://www.cnblogs.com/lyy-2016/p/5851597.html
Copyright © 2020-2023  润新知