Spring——装配Bean

Posted KLeonard

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring——装配Bean相关的知识,希望对你有一定的参考价值。

基本装配

在Spring容器内拼凑Bean叫做装配。装配Bean的时候,需要告诉哪些Bean以及容器如何使用依赖注入将它们配合在一起。

使用XML装配

XML是最常见的Spring应用系统配置源。

几种Spring容器都支持使用XML装配Bean,包括:

  1. XmlBeanFactory:调用ClassPathResource载入上下文定义文件(比如applicationContext.xml)。

  2. ClassPathXmlApplicationContext:从类路径载入上下文定义文件。

  3. XmlWebApplicationContext:从Web应用上下文中载入定义文件。

配置文件举例如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.gavin.ioc.Student" scope="singleton">
    <property name="name" value="Gavin"/>
</bean>
</beans>
  • 上下文定义文件的根元素是beans,有多个bean子元素。每个bean元素定义了一个bean如何被装配到Spring容器中。
  • 对bean的最基本的配置包括bean的ID和bean的全称类名。

scope

几种scope属性值:prototypesingletonrequestsessionglobal-session。Spring中的bean缺省情况下是单例模式。始终返回一个实例。若想返回不同的实例的话需要定义成原型模式。

作用域描述
singleton在每个Spring IoC 容器中一个Bean定义对应一个对象实例
prototype一个Bean定义对应多个实例
request在一个HTTP请求中,一个Bean定义对应一个对象实例;即每次HTTP请求都将会有各自的Bean实例,它们依据某个Bean定义创建而成。该作用域仅在基于Web的Spring Application情形下有效。
session在一个HTTP Session中,一个Bean定义对应一个对象实例。该作用域仅在基于Web的Spring Application情形下有效。
global-session在一个全局的HTTP Session中,一个Bean定义对应一个对象实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于Web的Spring Application情形下有效。

使用原型Bean会对性能产生影响,尽量不要设置为prototype,除非有必要。

实例化与销毁

Spring实例化bean或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法,即init-method方法和destory-method方法


Spring也提供了两个接口来实现相同的功能:InitializingBeanDisposableBeanInitializingBean接口提供了一个afterPropertiesSet()方法。DisposableBean接口提供了destroy()方法。

但是不推荐使用这两个接口,它会把Bean与Spring API绑定在一起。

通过set方法注入依赖

bean元素的property子元素指明了使用它们的set方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的Bean。

内部Bean

在property内部配置一个Bean,那么这个Bean只能被该属性引用。而不能被其他属性引用。

<bean id="outside" class="...">
    <property name="emp">
       <bean id="inside" class="...">
           <property name="" value=""/>
       </bean>
    </property>
</bean>

如上例所示,emp属性引用inside这个Bean,这里inside这个Bean只能被该emp属性引用,其他属性是不能引用的。

继承配置

Graduate类继承Student类,属性如下:

public class Student 
    protected int age;
    protected String name;
    ...
public class Graduate extends Student 
    private String degree;
    ...

配置如下:

<!--配置一个学生-->
<bean id="student" class="com.gavin.inherit.Student">
    <property name="age" value="18"/>
    <property name="name" value="Gavin"/>
</bean>
<bean id="graduate" parent="student" class="com.gavin.inherit.Graduate">
    <!--如果单独再配置name和age,则会覆盖从父对象继承的这个属性的值-->
    <property name="age" value="20"/>
    <property name="name" value="XiaoMing"/>
    <property name="degree" value="学士"/>
</bean>

给集合属性注入值

给数组或List集合注入值的配置方式如下:

Department有三个属性:

private String name;
private String[] empName;
private List employeeList;
<property name="empName">
    <list>
        <value>小明</value>
        <value>小红</value>
        <value>小亮</value>
    </list>
</property>
<property name="employeeList">
    <list>
        <ref bean="employee"/>
        <ref bean="employee1"/>
        <ref bean="employee2"/>
    </list>
</property>

给Set集合的注入与此类似:

<property name="employeeSet">
    <set>
        <ref bean="employee"/>
        <ref bean="employee1"/>
        <ref bean="employee2"/>
        <ref bean="employee2"/>
        <ref bean="employee2"/>
    </set>
</property>

给Map属性注入值

Map的注入也是类似的,不过稍有复杂而已:

Department中增加Map属性:

private Map employeeMap;

Spring中配置如下:

<property name="employeeMap">
    <map>
        <entry key="1" value-ref="employee"/>
        <entry key="2" value-ref="employee1"/>
        <entry key="3" value-ref="employee2"/>
    </map>
</property>

注入空值

<property name="barlist">
    <null/>
</property>

通过构造函数注入依赖

Employee对象如下:

public class Employee 
    private String name;
    private int age;

    public Employee() 
    

    public Employee(String name, int age) 
        System.out.println("Employee(String name, int age)函数被调用");
        this.name = name;
        this.age = age;
    

    public Employee(String name) 
        System.out.println("Employee(String name)函数被调用");
        this.name = name;
    

配置文件:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置一个Employee对象-->
    <bean id="employee" class="com.gavin.constructor.Employee">
        <!--通过构造函数来注入-->
        <constructor-arg index="0"  value="Gavin"/>
        <constructor-arg index="1"  value="19"/>
    </bean>
</beans>

也就是说,可以通过在bean元素下,配置constructor-arg元素来给构造函数传递参数。index用于指定参数的位置。

set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不可能实例化不完全的或无法使用的Bean。

如果属性是对象类型,则使用ref=”“

自动装配Bean的属性值

<bean id="foo" class="...Foo" autowire="autowire type">

有四种自动装配类型:

  1. byName:寻找和属性名相同的Bean,若找不到,则装不上。
  2. byType:寻找和属性类型相同的Bean,找不到,装不上,找到多个抛异常
  3. constructor:查找和bean的构造参数一致的一个或多个Bean,若找不到或找到多个,抛异常。按照参数的类型匹配。
  4. autodetect:(3)和(2)之间选一个方式。不确定性的处理与(3)和(2)一致。【3和2有先后顺序!】
  5. default:这个需要在beans中配置default-autowire="指定"。当在beans中指定了default-autowired之后,所有Bean的默认autowire方式就是该指定的装配方式。
  6. no:不自动装配,这是autowire的默认值

    • byName的案例:
public class Dog 
    private String name;
    private int age;
    ...


public class Master 
    private String name;
    private Dog dog;
    ...

Master中有Dog对象,配置如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--Master对象-->
    <bean id="master" class="com.gavin.autowire.Master" autowire="byName">
        <property name="name" value="Gavin"/>
    </bean>
    <!--Dog对象-->
    <bean id="dog" class="com.gavin.autowire.Dog">
        <property name="name" value="大黄"/>
        <property name="age" value="2"/>
    </bean>
</beans>

可以看到,master中并没有引用dog对象,而是设置了属性autowire=byName,这时Spring容器会根据属性名字寻找,找到属性名是dog的对象后,自动装配。

其他的也类似,比如byType是按照类型来寻找,那么不管Dog对象的属性名是什么,只要能找到一个Dog对象,就能自动装配。但是找到多个Dog对象就会抛出异常了。

  • constructor的话,需要在Master中写一个只有Dog参数的构造方法,那么Spring容器会将配置的Dog对象传递给这个构造函数。
public class Master 
    private String name;
    private Dog dog;

    public Master(Dog dog)
        this.dog = dog;
    
    ...

配置如下:

<bean id="master" class="com.gavin.autowire.Master" autowire="constructor">
        <property name="name" value="Gavin"/>
</bean>
<!--Dog对象-->
<bean id="dog" class="com.gavin.autowire.Dog">
    <property name="name" value="大黄"/>
    <property name="age" value="2"/>
</bean>

【注意】:自动装配能不用就不用!因为自动装配没有set注入或者构造函数注入明确。

使用Spring特殊的Bean

让Spring特殊对待这些Bean,使它们可以:
1.通过配置后加工Bean,涉及到Bean和Bean工厂生命周期。(比如BeanPostProcessor等)

2.改变依赖注入,将字符串转换成其它类型

3.从属性文本装载信息,包括信息国际化

4.监听并处理其它Bean及Spring发布的系统消息

5.知道自己在Spring中的唯一标识。

以上是关于Spring——装配Bean的主要内容,如果未能解决你的问题,请参考以下文章

Spring自动装配Bean的五种方式

Spring--自动装配

Spring IOC装配Bean

spring装配集合

spring自动装配bean入门教程

Spring Autowire自动装配