Spring Framework 源码学习笔记(三)

简介: Spring Framework 源码学习笔记(三)

Chapter 03 - Bean的生命周期

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

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

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

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

public void init(){
    System.out.println("Person Bean 初始化方法调用");
}
public void destroy(){
    System.out.println("Person Bean 销毁方法调用");
}
复制代码

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

@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

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

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

image.png

容器入口类AnnotationConfigApplicationContext

image.png

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

image.png

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

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

@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

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

@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

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

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

  1. 实现InitializingBean接口的afterPropertiesSet()方法,当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法
  2. 实现DisposableBean的destory()方法,当bean销毁时,会把单实例bean进行销毁 在entity包中新建一个Item实体类,实现InitializingBean和DisposableBean
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容器中

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

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

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

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

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

  • @PostConstruct: 在Bean创建完成,且属于赋值完成后进行初始化,属于JDK规范的注解
  • @PreDestroy: 在bean将被移除之前进行通知, 在容器销毁之前进行清理工作 在entity包中新增一个实体类Address
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

Section 05 - Bean生命周期之BeanPostProcessor

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

  • postProcessBeforeInitialization()
  • postProcessAfterInitialization()

image.png

自定义类CustBeanPostProcessor,实现BeanPostProcessor

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是第三种,

@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

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

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

@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实例也打印在控制台

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

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

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


相关文章
|
8天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的医学生在线学习交流平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的医学生在线学习交流平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
2天前
|
Java Spring
【JavaEE进阶】 Spring AOP源码简单剖析
【JavaEE进阶】 Spring AOP源码简单剖析
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的互助学习的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的互助学习的详细设计和实现(源码+lw+部署文档+讲解等)
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的用于日语词汇学习的微信小程的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的用于日语词汇学习的微信小程的详细设计和实现(源码+lw+部署文档+讲解等)
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的绘画学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的绘画学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的绘画学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的英语学习交流平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的英语学习交流平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
4天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
4天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的精品课程在线学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的精品课程在线学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
5天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的无纸化学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的无纸化学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
5天前
|
JavaScript Java 测试技术
基于springboot+vue.js的在线互动学习网站设计附带文章和源代码设计说明文档ppt
基于springboot+vue.js的在线互动学习网站设计附带文章和源代码设计说明文档ppt
11 0