Spring中Bean的“一生”(生命周期)

目录

一、Bean 实例化的基本流程

1、Bean 实例化的基本流程

2、Bean信息定义对象-BeanDefinition

3、Bean 实例化的基本流程 

二、Spring的后处理器

2、BeanPostProcessor

三、Spring Bean的生命周期

1、什么是SpringBean的生命周期

2、SpringBean的初始化过程 

3、SpringBean的生命周期阶段:

Spring的声明周期总体分为四个阶段:实例化=>属性注入=>初始化=>销毁。​编辑

3、Bean实例属性填充

四、常用的Aware接口

五、生命周期总结 


一、Bean 实例化的基本流程

1、Bean 实例化的基本流程

        Spring容器在进行初始化时,会将xml配置的的信息封装成一个BeanDefinition对象,所有的 BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架再对该Map进行遍 历,使用反射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用 getBean方法 时则最终从该Map集合中取出Bean实例对象返回。

2、Bean信息定义对象-BeanDefinition

BeanDefinition存储到一个名为beanDefinitionMap

 

对象存储在一个名为singletonObjects的Map

 

3、Bean 实例化的基本流程 
  • 加载xml配置文件,解析获取配置中的每个的信息封装成一个个的BeanDefinition对象;
  • 将BeanDefinition存储在一个名为beanDefinitionMap的Map中;
  • ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象;
  • 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map中;
  • 当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回

 

二、Spring的后处理器

        Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例 化之前执行;
  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects 之前执行。

1、BeanFactoryPostProcessor
(1)Bean工厂后处理器 – BeanFactoryPostProcessor
        BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

        演示修改:

  • 创建BeanFactoryPostProcessor实现类并重写方法
  • 注入实现类

 

实例代码(1):

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
 
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor的postProcessBeanFactory");
//        修改演示
//        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
//        beanDefinition.setBeanClassName("com.apesource.pojo.Student");
 
        // 注册演示
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.apesource.pojo.Student");
//        强转成DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        defaultListableBeanFactory.registerBeanDefinition("stu",beanDefinition);
    }
}

 这个MyBeanFactoryPostProcessor类实现了BeanFactoryPostProcessor接口,允许在Spring容器实例化任何Bean之前,对应用上下文中的Bean定义进行自定义修改。

        postProcessBeanFactory这是一个主要方法,其中进行Bean定义的自定义处理,Spring容器在加载完所有Bean定义后但在实例化任何Bean之前会调用这个方法。

        ConfigurableListableBeanFactory代表可配置的 BeanFactory 实例,可以用来获取和修改 BeanDefinition。

        首先是修饰演示,获取到已有的BeanDefinition并对其修改配置,这里是获取了id为user的bean并将bean的实现类改为com.apesource.pojo.Student,从而实现了修改。

        其次是注册演示,创建一个BeanDefinition对象,对这个对象使用set方法将bean的实现类设置为com.apesource.pojo.Student。然后把当前的ConfigurableListableBeanFactory创建的对象强为DefaultListableBeanFactory这是 Spring 中一种常见的 BeanFactory 实现类,它允许进行 Bean 的注册和删除。再调用DefaultListableBeanFactory的registerBeanDefinition方法,将刚才的BeanDefinition对象注册到 BeanFactory 中,并起名为stu。

        applicationContext.xml中配置:

<bean class="com.apesource.processor.MyBeanFactoryPostProcessor"></bean>

测试代码

public class Test01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object user = applicationContext.getBean("user");
        System.out.println(user);
    }
}

修饰演示的代码结果为:com.apesource.pojo.Student

(2)Bean工厂后处理器 – BeanDefinitionRegistryPostProcessor
        Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作。

        实例代码(2):

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {
 
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.apesource.pojo.Student");
        beanDefinitionRegistry.registerBeanDefinition("stu2",beanDefinition);
    }
 
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
 
    }
}

这里首先是继承了BeanDefinitionRegistryPostProcessor接口,那么我们就可以进行修改 BeanFactory 的配置,还可以直接注册新的 Bean 定义。

        重写了postProcessBeanDefinitionRegistry方法,该方法在 Spring 容器初始化期间调用,并传递一个 BeanDefinitionRegistry 实例,允许直接操作 Bean 定义注册表

        首先先创建了一个RootBeanDefinition对象,用来描述一个新的 Bean。然后向该对象设置这个bean的实现类为com.apesource.pojo.Student,最后使用registerBeanDefinition方法注册一个实现类为com.apesource.pojo.Student名叫stu的bean。

        它和上面的BeanFactoryPostProcessor的区别就是BeanDefinitionRegistryPostProcessor可以直接注册新的bean,而BeanFactoryPostProcessor需要强制转换后才能注册新的bean。

        applicationContext.xml中配置:

<bean class="com.apesource.processor.MyBeanFactoryPostProcessor2"></bean>

测试代码:

public class Test01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object stu = applicationContext.getBean("stu2");
        System.out.println(stu);
    }
}

         测试结果:com.apesource.pojo.Student@3108bc

2、BeanPostProcessor

Bean后处理器 – BeanPostProcessor

        Bean被实例化后,到最终缓存到名为singletonObjects单例池之前中间会经过Bean的初始化过程, 例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的 Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor, 会在流程节点上被Spring自动调用。

实例代码

// 接口允许开发者在 Spring 容器的 Bean 初始化前后,插入自定义的逻辑。
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor的before方法...");
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor的after方法...");
        return bean;
    }
}

  首先这个类实现了BeanPostProcessor接口,呢我们就可以在 Spring 容器中的 Bean 初始化之前和之后执行自定义逻辑

        第一个重写的方法postProcessBeforeInitialization这个方法会在 Bean 初始化方法(如 @PostConstruct 注解的方法或自定义的初始化方法)调用之前执行。两个参数分别为当前正在处理的 Bean 实例、当前 Bean 的名称。在处理完逻辑后,必须返回一个 Bean 对象。这里返回的是传入的原始 Bean,没有进行任何修改。

        第二个重写的方法是postProcessAfterInitialization这个方法会在 Bean 初始化方法调用之后执行。参数和上面的方法参数一致。同样返回传入的原始 Bean,没有进行任何修改。

        applicationContext.xml中配置:

<bean class="com.apesource.processor.MyBeanPostProcessor"></bean>

我们在刚才的代码进行优化,对实体类User进行构造方法等方法的写入

public class User implements InitializingBean {
    public User() {
        System.out.println("===》无参构造方法S");
    }
 
    private String uname;
 
    public void setUname(String uname) {
        this.uname = uname;
        System.out.println("===》执行set方法");
    }
 
    @Override
    public void afterPropertiesSet() throws Exception {
        // 这个接口定义了一个回调方法 afterPropertiesSet()。当 Spring 完成所有属性的注入后,容器会调用这个方法,用于进行一些初始化工作。
        System.out.println("===》接口初始化");
    }
 
    public void doinit(){
        System.out.println("===》属性初始化");
    }
}

其中实现了了InitializingBean接口用于重写afterPropertiesSet()方法,该方法会在所有属性(包括 uname)被注入后,由 Spring 容器自动调用,或者说是在 Bean 初始化阶段被调用

        doinit方法是自定义的初始化方法,可以通过 Spring 的 XML 配置或注解配置来调用,这个方法在 Spring 容器初始化完成后可以被显式调用,用于执行一些额外的初始化逻辑。

        那么我们在执行的时候顺序就为:

 

        首先是无参构造->执行set方法->然后是BeanPostProcessor的before方法->执行接口初始化->执行属性初始化->BeanPostProcessor的after方法->最后实例化成功,返回user对象地址。 

三、Spring Bean的生命周期

1、什么是SpringBean的生命周期

        Spring Bean的生命周期是从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:

Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是 singleton的, 是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的 Bean通过反射进行实例化;
Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执 行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段;
Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池 singletonObjects中去了,即完成了Spring Bean的整个生命周期。

2、SpringBean的初始化过程 

        由于Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段,Spring Bean的初始化过程涉及如下几个过程:

  • Bean实例的属性填充
  • Aware接口属性注入
  • BeanPostProcessor的before()方法回调
  • InitializingBean接口的初始化方法回调
  • 自定义初始化方法init回调
  • BeanPostProcessor的after()方法回调
3、SpringBean的生命周期阶段:
Spring的声明周期总体分为四个阶段:实例化=>属性注入=>初始化=>销毁
  • Spring Bean 的生命周期总体分四个阶段:实例化=>属性注入=>初始化=>销毁
  • Step1实例化Bean:根据配置文件中Bean 的定义,利用Java Reflection反射技术创建Bean的实例
  • Step2注入对象依赖的属性值(或对象)
  • Step3处理各种Aware接口:Spring 会检测该Bean是否实现了xxxAware接口,通过(Aware类型的接口,可以让Spring框架为当前Bean注入相应的内容。
    • 如果Bean实现 BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,注入Bean的名字;
    • 如果 Bean实现 BeanclassLoaderAware接口,调用setBeanClassLoader()方法,注入classLoader对象的实例;
    • 如果Bean实现BeanFactoryAware 接口,会调用它实现的setBeanFactory()方法,注入的是Spring工厂;
    • 如果 Bean实现 ApplicationContextAware接口,会调用setApplicationContext()方法,注入Spring上下文;
  • Step4执行BeanPostProcessor前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean 实现了(BeanPostProcessor接口,将会在该阶段调用postProcessBeforeInitialization(Object obj,string s)方法。
  • Step5执行InitializingBean初始化方法:如果Bean 实现了InitializingBean接口,执行afeterPropertiesSet()方法。
  • Step6执行init-method自定义初始化方法:如果Bean 在 Spring 配置文件中配置了init-method属性,则会自动调用其配置的初始化方法。
  • .Step7执行BeanPostProcessor后置处理:如果这个 Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(0bject obj,string s)方法,由于这个方法是在 Bean初始化结束后调用;
  • 以上几个步骤完成后,|Bean已经被正确创建,可以正常使用这个Bean
  • Step8执行DisposableBean销毁Bean:当Bean 不再需要时,会经过清理阶段,如果Bean 实现了DisposableBean这个接口,会调用其实现的destroy()方法执行销毁;
  • Step9执行destroy-method自定义销毁方法:如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的自定义销毁方法。
3、Bean实例属性填充

        BeanDefinition 中有对当前Bean实体的注入信息通过属性propertyValues进行了存储,例如:

总结:Spring在进行属性注入时,会分为如下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)

   多例含义:多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用";

public class DefaultSingletonBeanRegistry ... {
 //1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
 Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
 //2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
 Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
 //3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"
 Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,未来通过此接口对应的get方法再
次提取对象

 

解决方案

        Spring提供了三级缓存存储完整Bean实例和半成品Bean实例,用于解决循环引用问题在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

public class DefaultSingletonBeanRegistry ... {
 //1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
 Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
 //2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
 Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
 //3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"
 Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,未来通过此接口对应的get方法再
次提取对象

 UserService和UserDao循环依赖的过程结合上述三级缓存描述一下:

  • UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
  • UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
  • UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
  • UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移 入二级缓存;
  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
  • UserService 注入UserDao;
  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存。

一级缓存:存储的是完整的、初始化后的单例(Singleton)Bean 实例。

二级缓存:存储的是早期的 Bean 实例,通常是已经实例化但还未进行完全初始化(如未完成属性填充)的 Bean。

三级缓存:存储的是一个 Bean 的工厂对象,用于创建半成品的 Bean 实例(通常是代理对象)。

四、常用的Aware接口

        Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封装性,我们接触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用不到这些对象,如果用到了,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象。

处理器的作用,为Bean生命周期各个阶段提供扩展。

        实例代码:

public class User implements BeanNameAware, ApplicationContextAware, BeanFactoryAware {
 
    // BeanFactoryAware接口
    // 当 Spring 容器创建 User Bean 时,会调用这个方法,并传递当前的 BeanFactory 实例作为参数。控制台会输出这个 BeanFactory 的信息。
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(beanFactory);
    }
 
    // BeanNameAware
    // 当 Spring 创建并配置 User Bean 时,会调用这个方法,并将 Bean 的名称作为参数传递给它。控制台会输出该名称,即 "s"。
    @Override
    public void setBeanName(String s) {
        System.out.println(s);
    }
 
    // ApplicationContextAware
    // 当 Spring 容器创建 User Bean 时,会调用这个方法,并传递当前的 ApplicationContext 实例作为参数。控制台会输出这个 ApplicationContext 的信息。
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }
 
    // 顺序setBeanName setBeanFactory setApplicationContext
}

这个类实现了BeanNameAware、ApplicationContextAware和BeanFactoryAware它们提供了一些回调方法,使 Bean 可以在初始化过程中获取 Spring 容器的相关信息。

        setBeanFactory方法是当 Spring 容器创建 User Bean 时,会调用此方法,并将当前的 BeanFactory 实例作为参数传递给它。

        setBeanName方法是当 Spring 容器创建并配置 User Bean 时,会调用此方法,并将 Bean 的名称作为参数传递给它。

        setApplicationContext方法是当 Spring 容器创建 User Bean 时,会调用此方法,并将当前的 ApplicationContext 实例作为参数传递给它。

        三者的方法调用顺序为:setBeanName(先设置 Bean 的名称)-> setBeanFactory(然后传递 BeanFactory 实例)-> setApplicationContext(最后传递 ApplicationContext 实例)。

        测试代码:

public class Test01 {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object user = applicationContext.getBean("users");
        System.out.println(user);
    }
 
}

结果为:

五、生命周期总结 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值