前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Framework 源码学习笔记(三)

Spring Framework 源码学习笔记(三)

作者头像
RiemannHypothesis
发布2022-08-19 15:58:26
2040
发布2022-08-19 15:58:26
举报
文章被收录于专栏:Elixir

Chapter 03 - Bean的生命周期

Bean的声明周期是指Bean创建➡️初始化➡️销毁的过程

XML配置注册Bean时,bean标签除了id class属性还有init-method和destroy-method,这两个方法就是配置bean的初始化方法和销毁方法

Section 01 - 单实例Bean的生命周期

以Person实体类为例,增加初始化方法和销毁方法,自定义Bean初始化和销毁

代码语言:javascript
复制
public void init(){
    System.out.println("Person Bean 初始化方法调用");
}

public void destroy(){
    System.out.println("Person Bean 销毁方法调用");
}

在config包中定一个BeanLifeCycleConfig配置类,声明了initMethod和destroyMethod,注意不要加(),代码如下

代码语言:javascript
复制
@Configuration
public class BeanLifeCycleConfig {

    @Bean(value = "stark", initMethod = "init", destroyMethod = "destroy")
    public Person stark(){
        System.out.println("stark被实例化");
        Person person = new Person();
        person.setName("stark");
        person.setAge(40);
        return person;
    }
}

在test包中新增一个BeanLifeCycleTest

代码语言:javascript
复制
public class BeanLifeCycleTest {

    @Test
    public void getBeanByImport(){
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
        System.out.println("IoC容器初始化完成");
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        // 关闭容器
        ((AnnotationConfigApplicationContext)context).close();
    }
}

执行测试

image.png
image.png

close()方法底层最终调用的是map的clear()方法,也就是清空map容器

image.png
image.png

容器入口类AnnotationConfigApplicationContext

image.png
image.png

容器创建Bean最终是调用的BeanUtils的instantiateClass()方法,该方法中使用了反射中的newInstance方法来实例化Bean

image.png
image.png

Section 02 - 多实例Bean的生命周期

在配置类中@Bean注解中配置多实例

代码语言:javascript
复制
@Configuration
public class BeanLifeCycleConfig {

    @Scope("prototype")
    @Bean(value = "stark", initMethod = "init", destroyMethod = "destroy")
    public Person stark(){
        System.out.println("stark被实例化");
        Person person = new Person();
        person.setName("stark");
        person.setAge(40);
        return person;
    }
}

执行测试,初始化和销毁方法都没有调用

image.png
image.png

多实例时只有调用getBean()方法时才会创建Bean,修改测试方法,增加获取Bean的代码

代码语言:javascript
复制
@Test
public void getBeanByImport(){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
    System.out.println("IoC容器初始化完成");
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
    Person bean = context.getBean(Person.class);
    // 关闭容器
    context.close();

}

控制台打印如下,只调用了初始化方法

image.png
image.png

对于多实例的bean,容器只负责初始化, 但不会管理bean, 容器关闭时不会调用销毁方法

Section 03 - 自定义Bean生命周期的第二种方式

  1. 实现InitializingBean接口的afterPropertiesSet()方法,当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法
  2. 实现DisposableBean的destory()方法,当bean销毁时,会把单实例bean进行销毁 在entity包中新建一个Item实体类,实现InitializingBean和DisposableBean
代码语言:javascript
复制
public class Item implements InitializingBean, DisposableBean {

    private Integer id;
    private String itemName;

    public Item(Integer id, String itemName) {
        System.out.println("Item 有参构造方法被调用");
        this.id = id;
        this.itemName = itemName;
    }

    public Integer getId() {
        System.out.println("getId()方法被调用");
        return id;
    }

    public void setId(Integer id) {
        System.out.println("setId()方法被调用");
        this.id = id;
    }

    public String getItemName() {
        System.out.println("getItemName()方法被调用");
        return itemName;
    }

    public void setItemName(String itemName) {
        System.out.println("setItemName()方法被调用");
        this.itemName = itemName;
    }

    public Item(){
        System.out.println("Item 空参构造方法被调用");
    }

    // Bean销毁时调用
    @Override
    public void destroy() throws Exception {
        System.out.println("Item Bean 销毁方法被调用");
    }

    // Bean属性赋值和初始化完成后调用
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Item Bean 初始化方法被调用,属性被赋值后调用");
    }
}
复制代码

修改BeanLifeCycleConfig配置类,增加@Import注解,把Item注册到IoC容器中

代码语言:javascript
复制
@Configuration
@Import(value = Item.class)
public class BeanLifeCycleConfig {
}
复制代码

注释BeanLifeCycleTest测试类方法中获取Person Bean的代码

代码语言:javascript
复制
public class BeanLifeCycleTest {

    @Test
    public void getBeanByImport(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
        System.out.println("IoC容器初始化完成");
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        // Person bean = context.getBean(Person.class);
        // 关闭容器
        context.close();

    }
}
复制代码

执行测试,查看控制台打印结果

image.png
image.png

Section 04 - 自定义Bean生命周期的第三种方式

可以使用JSR250规则定义的(java规范)两个注解来实现

  • @PostConstruct: 在Bean创建完成,且属于赋值完成后进行初始化,属于JDK规范的注解
  • @PreDestroy: 在bean将被移除之前进行通知, 在容器销毁之前进行清理工作 在entity包中新增一个实体类Address
代码语言:javascript
复制
public class Address {

    private Integer id;
    private String addressDetail;

    public Address() {
        System.out.println("Address空参构造方法被调用");
    }

    public Address(Integer id, String addressDetail) {
        System.out.println("Address有参数构造方法被调用");
        this.id = id;
        this.addressDetail = addressDetail;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAddressDetail() {
        return addressDetail;
    }

    public void setAddressDetail(String addressDetail) {
        this.addressDetail = addressDetail;
    }

    @PostConstruct
    public void init(){
        System.out.println("Address Bean 的 @PostContruct注解形式的Bean初始化方法");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("Address Bean 的 @PreDestry注解形式的Bean销毁方法");
    }
}
复制代码

修改BeanLifeCycleConfig方法@Import注解,改@Import(Address.class),即往容器中注入Address Bean,BeanLifeCycleTest类不需要修改,直接执行测试方法,控制它打印如下

image.png
image.png

Section 05 - Bean生命周期之BeanPostProcessor

  Bean的后置处理器,在bean初始化之前调用进行拦截,在bean初始化前后进行一些处理工作,使用BeanPostProcessor如何控制Bean的生命周期,实现BeanPostProcessor的两个接口即可

  • postProcessBeforeInitialization()
  • postProcessAfterInitialization()
image.png
image.png

自定义类CustBeanPostProcessor,实现BeanPostProcessor

代码语言:javascript
复制
public class CustBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "postProcessBeforeInitialization前置处理器调用");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "postProcessAfterInitialization后置处理器调用");
        return bean;
    }
}
复制代码

修改BeanLifeCycleConfig,将自定义的CustBeanPostProcessor注册到容器中,在注册一些其他的Bean,Person是使用第一种生命周期定义方式,Item是第二种,Address是第三种,

代码语言:javascript
复制
@Configuration
//@Import(value = Item.class)
//@Import(value = Address.class)
@Import({CustBeanPostProcessor.class, Item.class, Address.class})
public class BeanLifeCycleConfig {


    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Person person(){
        System.out.println("Person Bean被实例化");
        Person person = new Person();
        person.setName("Stark");
        person.setAge(40);
        return person;
    }
}
复制代码

执行测试类,确定postProcessBeforeInitialization(),postProcessAfterInitialization()是否支持这三种初始化方法前后调用

image.png
image.png

CustBeanPostProcessor的初始化前后拦截是针对容器中的所有业务Bean,不包括它本身

多实例情况下如何?修改BeanLifeCycleConfig,给Person添加多实例注解@Scope

代码语言:javascript
复制
@Configuration
//@Import(value = Item.class)
//@Import(value = Address.class)
@Import({CustBeanPostProcessor.class, Item.class, Address.class})
public class BeanLifeCycleConfig {
    
    @Scope("prototype")
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Person person(){
        System.out.println("Person Bean被实例化");
        Person person = new Person();
        person.setName("Stark");
        person.setAge(40);
        return person;
    }
}

在打印方法中添加bean,将Bean实例也打印在控制台

代码语言:javascript
复制
public class CustBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "postProcessBeforeInitialization前置处理器调用" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "postProcessAfterInitialization后置处理器调用" + bean);
        return bean;
    }
}

在BeanLifeCycleTest中两次获取Person Bean

代码语言:javascript
复制
public class BeanLifeCycleTest {

    @Test
    public void getBeanByImport(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
        System.out.println("IoC容器初始化完成");
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        Person bean = context.getBean(Person.class);
        Person bean1 = context.getBean(Person.class);

        // 关闭容器
        context.close();

    }
}

查看控制台打印

image.png
image.png

自定义CustBeanPostProcessor对初始化方法的前后拦截针对多实例Bean同样适用

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Chapter 03 - Bean的生命周期
    • Section 01 - 单实例Bean的生命周期
      • Section 02 - 多实例Bean的生命周期
        • Section 03 - 自定义Bean生命周期的第二种方式
          • Section 04 - 自定义Bean生命周期的第三种方式
            • Section 05 - Bean生命周期之BeanPostProcessor
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档