Spring Bean


Spring IoC容器可以创建、装配、配置应用组件对象,这里的组件对象称为Bean。

1.Bean 的配置

Spring可以看作一个工厂,用于生产和管理Spring容器中的Bean。

如果要使用这个工厂生产和管理Bean,需要将Bean配置在Spring的配置文件中。支持 XML 和 Properties 两种格式的配置文件,常用 XML格式。

元素的常用属性及其子元素:

属性或子元素 描述
id Bean在BeanFactory中的唯一标识,在代码中通过BeanFactory获取Bean实例时需要依次作为索引名称
class Bean的具体实现类,例如dao.TestDIDaoImpl
scope 指定Bean实例的作用域
< property> 用于设置一个属性。name 指定Bean实例中相应的属性名称、value 指定Bean的属性值、ref 指定属性对BeanFactory中其他Bean的引用关系
< constructor-arg> 使用构造方法注入,指定构造方法的参数。index指定参数的序号,ref指定对BeanFactory中其他Bean的引用关系,type指定参数类型,value指定参数的常量值
< map>、 < set> 的子元素,封装对应类型的依赖注入
< list> 的子元素,封装List 、数组类型的依赖注入
< entry> 的子元素,用于设置一个键值对

2.Bean 的实例化

在面向对象编程时,如果要使用某个对象,需要事先实例化该对象。Spring中,也需要先实例化Bean。

有3种方式:构造方法实例化、静态工厂实例化、实例工厂实例化。最常用构造方法实例化

2.1构造方法实例化

Spring容器调用Bean对应类中的无参数构造方法来实例化Bean。

创建BeanClass类

package instance;
public class BeanClass {
    public String message;
    public BeanClass() {
        message = "构造方法实例化Bean";
    }
    public BeanClass(String s) {
        message = s;
    }
}

创建配置文件applicationContext.xml

<!-- 构造方法实例化Bean -->
<bean id="demo" class="instance.BeanClass"/>

创建测试类

package test;
public class TestInstance {
    public static void mani(String[] args) {
        ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanClass b = (BeanClass)appCon.getBean("demo");
        System.out.println(b1 + b1.message);
    }
}

结果:instance.BeanClass@490ab905构造方法实例化Bean

3.Bean的作用域

scope参数 描述
singleton 默认的作用域,定义的Bean在Spring容器中只有一个Bean实例(返回同一个)
prototype Spring容器每次获取Bean,都将创建一个新的Bean实例(每次都返回新的)
request 每次HTTP请求都会返回一个Bean实例
session 在一个session中,将返回同一个Bean实例
application 为每个ServletContext对象创建一个实例,即同一个应用共享一个
websocket 为每个WebSocket对象创建一个实例

singleton 与 prototype是最常用的,后面4种仅在Web Spring应用上下文中使用。

4.Bean的生命周期

一个对象的生命周期包括:创建(实例化与初始化)、使用、销毁。Bean也遵循这一过程。但是Spring通过了许多对外接口,允许开发者对 实例化(开辟空间)、初始化(属性初始化)、销毁 3个过程的前后做一些操作。

Spring容器可以管理singleton作用域下Bean的生命周期,能够精确知道Bean何时被创建,何时初始化完成,何时被销毁。而对于prototype作用域下的Bean,Spring只负责创建。创建之后Bean实例就交给客户端的代码管理,Spring将不再跟踪其生命周期,也不会管理这些Bean。

Bean的生命周期:

  1. 根据Bean的配置情况实例化一个Bean。

  2. 根据Spring上下文对实例化的Bean进行依赖注入,即对Bean的属性进行初始化

  3. 如果Bean实现了 BeanNameAware接口,将调用它实现的 setBeanName(String beanId)方法,此处参数传递的是Bean的id,让实现这个接口的Bean知道自己在Spring容器中的的名字。

  4. 如果Bean实现了 BeanFactoryAware接口,将调用它实现的 setBeanFactory方法,此处参数传递的是当前Spring工厂实例的引用。此接口是在Bean实例化后、Setter方法之前调用。可以使得Bean获取容器的内部信息,从而进行某些定制化的操作。

  5. 如果Bean实现了 ApplicationContextAware接口,将调用它实现的setApplicationContext(ApplicationContext)方法,此处参数传递的是Spring上下文实例的引用。该方法会将容器本身作为参数传给该方法,将Spring传入的参数赋给该类对象的applicationContext实例变量,接下来可以通过该变量来访问容器本身。

  6. 如果Bean关联了 BeanPostProcessor接口,将调用初始化方法 postProcessBeforeInitialization(Object obj, String beanName)对Bean进行前置处理。BeanFactoryPostProcessor是Bean属性处理容器,管理所有未实例化的数据(修改属性)。

  7. 如果Bean实现了 InitializingBean接口,将调用 afterPropertiesSet方法。

  8. 如果Bean在Spring配置文件中配置了 init-method属性,将自动调用其配置的初始化方法。

    注意:Spring为Bean提供了两种初始化方式:实现InitializingBean接口、init-method指定。

    ​ 两种方式可以同时使用,但如果调用afterPropertiesSet时出错,则不会调用init-method指定的方法。

    ​ 通过反射调用init-method指定的方法效率相对较低,但是消除了对Spring的依赖。

  9. 如果Bean关联了 BeanPostProcessor接口,将调用 postProcessAfterInitialization(Object obj, String beanName)方法进行后置处理,由于是在Bean初始化结束时调用After方法,也可用于内存或缓存技术。

    注意:此时已经可以使用该Bean,由于该Bean的作用域是singleton,所以调用的是同一个Bean实例。

  10. 当Bean不再需要时将进入销毁阶段,如果Bean实现了 DisposableBean接口,则调用其实现的destroy方法将Bean销毁

  11. 如果在配置文件中通过 destroy-method属性指定了Bean的销毁方法,将调用其配置的销毁方法进行销毁

实例演示:

package life;
public class BeanLife {
    public void initMyself() {
        System.out.println(this.getClass().getName() + "执行自定义的初始化方法");
    }
    public void destroyMyself() {
        System.out.println(this.getClass().getName() + "执行自定义的销毁方法");
    }
}
<!-- 使用init-method属性指定初始化方法,使用destroy-method属性指定销毁方法-->
<bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method="destroyMyself"/>
package test;
public class TestLife {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanLife blife = (BeanLife)ctx.genBean("beanLife");
        System.out.println("获得对象后" + blife);
        // 关闭容器,销毁Bean对象
        ctx.close();
    }
}

5.Bean的装配

Bean的装配可以理解为将Bean依赖注入到Spring容器中。Spring容器支持:基于XML配置、基于注解、自动装配等多种装配方式,最常见的是基于注解。

5.1基于注解的装配

尽管使用XML配置文件可以很简单的装配Bean,但如果有大量的Bean,会导致XML配置文件过于庞大,不方便升级与维护,因此更推荐使用注解(annotation)。

  • @Repository

    将数据访问层(DAO)的类标识为Bean。

  • @Service

    将业务逻辑组件类(Service层)标注为Bean。

  • @Controller

    将控制器组件类标注为Bean。

  • @Component

    可以作用在任何层次上,标注一个Bean。为了更加层次化,不推荐使用。

  • @Autowired

    类成员变量、方法、构造方法进行标注,完成自动装配工作。可以消除setter和getter方法。默认按照Bean的类型进行装配,如果想按照名称装配,需要和@Qualifier 一起使用

  • @Resource(name=” “)

    与@Autowired 功能一样,区别在于该注解默认是按照名称来装配注入的,只有找不到与名称匹配的Bean时才会按照Bean的类型来装配注入。@Resource有两个属性:name、type。name指定Bean实例名称,即按照名称来装配;type指定类型,即按照类型来装配。

  • @Qualifier

    与@Autowired配合使用,当需要按照名称装配时。Bean的实例名称由@Qualifier 的参数指定。


  TOC