Spring 02: Bean概览

Spring Bean是什么?

在 Spring 中,Bean 是一个由 Spring IoC(控制反转)容器管理的对象。Bean 通常通过在 XML 配置文件、Java 配置类或基于注解的方式定义,并由容器负责创建和配置。Spring 容器负责管理 Bean 的整个生命周期,从创建、配置到销毁。这种管理包括依赖注入、生命周期回调等。

Bean别名

<bean id="bookDao" class="space.mora.dao.impl.BookDaoImpl"/>  
<bean id="bookService" name="service service2" class="space.mora.service.impl.BookServiceImpl"> 
    <property name="bookDao" ref="bookDao"/> <!--配置依赖  name是指class中的属性名称,ref是指依赖bean的id -->  
</bean>

<bean>标签的name属性可以用来指定bean的别名,别名之间可以使用逗号、分号、空格进行分割,定义的别名可以用于API获取bean,以及XML中其他地方对该bean进行引用。

Bean非单例(配置控制范围)

Spring通过<bean>标签声明的bean默认为单例,即只创建一个对象。

  • 为什么Bean默认为单例?
    答:限制Bean创建实例的数量。并且单例作用域下,Bean可以在ApplicationContext被创建之后就进行预创建,此时依赖或声明配置异常可以提前抛出,而不是等程序运行一段时间之后,再在创建Bean对象时抛出。(有点类似于fast-fail的理念)
  • 适合交给容器进行管理的bean
    • 表现层对象
    • 业务层对象
    • 数据层对象
    • 工具对象
  • 不适合交给容器管理的bean
    • 封装实体的域对象

如何创建以非单例的形式来创建bean?

  • <bean>标签的scope属性,设置为prototype(默认为singleton),若如此,创建的bean每次getBean时拿到的是不同的对象。

Bean对象创建时机

默认情况下,所有bean在IOC容器启动之后即被创建。
但是,当<bean>的属性lazy-init被设置为true(启用懒加载),或者scope被设置为prototype时(非单例),这些对象只有被使用到的时候才会创建ctx.getBean(...)

Bean实例化的三种形式

  1. 使用无参构造
    直接使用普通的<bean>标签创建时,使用无参构造函数创建类实例。且无论该无参构造的访问控制属性,即便是private也可成功调用,这是因为底层实现借助了反射机制。请注意必须提供无参构造,否则抛BeanCreationException

  2. 使用静态工厂
    <bean>标签的class属性指向静态工厂类,额外配置factory-method属性说明工厂方法名即可。

<bean id="orderDao2" class="space.mora.factory.OrderDaoFactory" factory-method="getOrderDao"/>
  1. 使用实例工厂
    在配置中,先创建实例工厂Bean,再创建目标Bean实例。
<bean id="userDaoFactory" class="space.mora.factory.UserDaoFactory"/>  
<bean id="userDao1" factory-bean="userDaoFactory" factory-method="getUserDao"/>
  1. 实例工厂模式简化

工厂类实现FactoryBean接口,可一步到位完成配置。该接口配置如下:

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception; // 创建对象并返回

    @Nullable
    Class<?> getObjectType(); // 返回被创建对象的类class

    default boolean isSingleton() {
        return true; // 控制是否单例
    }
}

Tips: 容器只负责管理 FactoryBean 实例的生命周期,而不负责管理由 FactoryBean 创建的对象的生命周期。因此,不会自动调用公开的 bean 对象(例如 Closeable.close ())上的销毁方法。相反,FactoryBean 应该实现 DisposableBean,并将任何此类关闭调用委托给底层对象。

使用FactoryBean后,XML中的<bean>标签仅需用class指定实现的FactoryBean非抽象类即可。

<bean id="userDao2" class="space.mora.factory.UserDaoFactoryBean"/>

注意:使用普通实例工厂,Bean实例化默认在IOC容器启动时;而使用FactoryBean实例化Bean时,默认在ctx.getBean进而调用FactoryBean#getObject()时,即属于懒加载模式。

Tips: 当然具体看你FactoryBean接口怎么实现,如果你在接口类中声明静态实例,在getObject时返回该静态实例,那么此种情况下,也相当于容器启动时创建。

Bean生命周期控制

bean生命周期如下:

    1. 创建对象(分配内存)
    1. 执行构造方法
    1. 执行依赖注入(set操作)
    1. 执行生命周期回调中的init-method
    1. 当容器被关闭或销毁时,执行destory-method

我们可以借助Bean的生命周期回调来控制Bean在属性设置完成以及销毁前的行为。主要有以下两种形式:

  1. XML配置
    通过<bean>标签的init-method属性和destory-method属性,指定初始化回调和销毁回调。需要注意的是,销毁回调函数只有当ClassPathXmlApplicationContextclose方法被调用时,才会进行回调。而通常情况下,我们引用容器实例的ApplicationContext属于上层接口,没有close方法。

因此,想要销毁回调正常被调用的话,首先需要用ClassPathXmlApplicationContext去引用容器实例,然后

  • 要么在最后调用close关闭容器
  • 要么在创建容器之后,调用registerShutdownHook方法注册销毁回调钩子
  1. 实现Spring提供的接口

除了使用钩子外,还可以实现Spring的生命周期回调接口中的方法配置回调。
实例化回调可以实现InitializingBean接口中的afterPropertiesSet方法。
销毁回调可以实现DisposableBean接口中的destroy方法。
当然,这种方式配置的回调仍然需要关闭容器或注册销毁钩子。

Tips: Spring官方文档并不建议用这种方式,因为这会破坏Spring的非侵入特性。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值