Spring注解版--Bean的生命周期

Spring注解--Bean的声明周期

    • @[TOC](Spring注解--Bean的声明周期)
  • Bean的生命周期
    • 1.Bean的生命周期:
    • 2.Spring容器来管理Bean的生命周期:
      • 2.1、指定初始化和销毁方法
        • 2.1.1、创建bean对象
        • 2.1.2、创建配置类
        • 2.1.3、创建测试类测试
      • 2.2、实现`InitializingBean`(定义初始化逻辑)与`DisposableBean`(定义销毁逻辑)
        • 2.2.1、创建bean对象
        • 2.2.2、创建配置类
        • 2.2.3、创建测试类测试
      • 2.3、使用JSR250(在Bean对象的类文件中标注)
        • 2.3.1、创建bean对象
        • 2.3.2、创建配置类
        • 2.3.3、创建测试类测试
      • 2.4、`BeanPostProcessor`-bean的后置处理器(接口)
        • 2.4.1、创建实现类
        • 2.4.2、环境配置
        • 2.4.3、运行测试
    • 3.构造(对象创建)
    • 4.初始化具体过程
    • 5、源码分析`BeanPostProcessor`

最近,学习Spring注解的时候,看完晚上的教学视频,在此将Spring注解的Bean的生命周期这一章的内容写下来,方便以后自己会看。


Bean的生命周期

1.Bean的生命周期:

​ Bean创建-------->Bean初始化-------->Bean销毁

2.Spring容器来管理Bean的生命周期:

​ 自定义初始化和销毁的方法:容器在Bean进行到当前生命周期的时候来调用我我们自定义的初始化和销毁方法。

2.1、指定初始化和销毁方法

  • xml文件的配置方式中,我们可以在标签中添加init-method以及destory-method这两个属性,指定初始化和销毁的方法。
  • 注解编程中,我们在方法中添加@BeaninitMethod以及destoryMethod这两个属性,指定初始化和销毁的方法。

2.1.1、创建bean对象

​ 我们在bean文件包下面创建一个Car类文件,内部有一个无参构造器、一个初始化方法以及一个销毁方法。

package com.xiaojian.bean;

public class Car {

    public Car(){
        System.out.println("car...constructor");
    }

    public void init(){
        System.out.println("car...init");
    }

    public void destory(){
        System.out.println("car...destory");
    }
}

2.1.2、创建配置类

​ 我们在config文件包下面创建一个MainConfig1类文件,内部有一个bean。

package com.xiaojian.config;

import com.xiaojian.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class MainConfig1 {
    
//    @Scope("prototype")  //此为多实例
    @Bean(value = "car",initMethod = "init",destroyMethod = "destory")
    public Car car(){
        return new Car();
    }

}

2.1.3、创建测试类测试

​ 我们在test文件包下面创建MainTest1测试类文件。

package com.xiaojian.test;

import com.xiaojian.config.MainConfig1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest1 {

    public static void main(String[] args) {

        //1、创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig1.class);
        System.out.println("IOC容器创建完成");

        Object car = applicationContext.getBean("car");
        System.out.println("car的bean创建完成");

        //2、关闭容器
        applicationContext.close();
        System.out.println("IOC容器关闭");
    }
}

  • 单实例测试结果:
D:\basic\jdk\jdk1.8.0_131\bin\java ...
car...constructor
car...init
IOC容器创建完成
car的bean创建完成
car...destory
IOC容器关闭

Process finished with exit code 0

​ 如上,为控制台打印的日志文件,可以看出来在单实例的情况下,bean对象在IOC容器初始化完成之前就已经创建完成,同时初始化方法init在bean对象创建完成之后直接运行,等容器关闭的时候destory方法运行。

  • 多实例测试结果:
D:\basic\jdk\jdk1.8.0_131\bin\java ...
IOC容器创建完成
car...constructor
car...init
car的bean创建完成
IOC容器关闭

Process finished with exit code 0

​ 如上,为控制台打印的日志文件,可以看出来在多实例的情况下面,IOC容器创建的时候bean对象并没有被创建,而是等到我们容器调用这个bean的时候才创建这个bean,同时运行init这个初始化方法,但是多实例的容器的销毁方法不会运行,也就是IOC容器不管理多实例的bean的销毁。

2.2、实现InitializingBean(定义初始化逻辑)与DisposableBean(定义销毁逻辑)

​ 让Bean对象实现InitializingBean接口,重写它的afterPropertiesSet()方法;同时让bean对象实现DisposableBean接口,重写它的destroy()方法来定义销毁逻辑。

2.2.1、创建bean对象

​ 我们在bean文件包下面创建一个Cat类文件,此类实现InitializingBeanDisposableBean这两个接口,并且重写对应的方法,同时此类本身有一个无参构造器。

package com.xiaojian.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

//此处使用@Component注解将此bean加入到IOC容器中(也可以在配置类中通过添加@Bean的方式添加)
@Component
public class Cat  implements InitializingBean,DisposableBean{

    public Cat(){
        System.out.println("cat...constructor");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("cat...destory");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat...afterPropertiesSet");
    }
}

2.2.2、创建配置类

​ 我们在config文件包下面创建一个MainConfig2类文件,此配置类中没有bean对象的方法,而是添加了@ComponentScan注解来扫描bean对象。

package com.xiaojian.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//通过注解@ComponentScan注解扫描bean文件包下面的所有配置文件
@ComponentScan("com.xiaojian.bean")
@Configuration
public class MainConfig2 {
}

2.2.3、创建测试类测试

​ 我们在test文件包下面创建MainTest2测试类文件。

package com.xiaojian.test;

import com.xiaojian.config.MainConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest2 {

    public static void main(String[] args) {

        //1、创建IOC容器
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("IOC容器创建完成");

        System.out.println("IOC容器关闭");
        applicationContext.close();
    }
}

​ 测试结果:

D:\basic\jdk\jdk1.8.0_131\bin\java ...
cat...constructor
cat...afterPropertiesSet
IOC容器创建完成
IOC容器关闭
cat...destory

Process finished with exit code 0

​ 如上,未控制台打印的日志文件,可以看出来,在IOC容器初始化之前就已经创建好了bean对象,使用了afterPropertiesSet初始化方法,在IOC容器关闭的时候使用了destory销毁方法。

2.3、使用JSR250(在Bean对象的类文件中标注)

  1. @PostConstruct:在Bean创建完成并且属性赋值完成之后来执行初始化方法。
  2. @PreDestory:在容器销毁Bean之前通知我们进行清理工作。

2.3.1、创建bean对象

​ 我们在bean文件包下面创建一个Dog类文件,内部有一个无参构造器,一个init方法,一个destory方法。同时init方法添加上注解@PostConstructdestory方法添加上注解@PreDestory

package com.xiaojian.bean;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//此处使用@Component注解将此bean加入到IOC容器中
// (也可以在配置类中通过添加@Bean的方式添加)
@Component
public class Dog {

    public Dog(){
        System.out.println("dog...constructor");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("dog...@PostConstruct");
    }

    //在容器销毁之前调用
    @PreDestroy
    public void destory(){
        System.out.println("dog...@PreDestory");
    }
}

2.3.2、创建配置类

​ 我们在config文件包下面创建一个MainConfig3类文件,此配置类中没有bean对象的方法,而是添加了@ComponentScan注解来扫描bean对象。

package com.xiaojian.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//通过注解@ComponentScan注解扫描bean文件包下面的所有配置文件
@ComponentScan("com.xiaojian.bean")
@Configuration
public class MainConfig3 {
}

2.3.3、创建测试类测试

​ 我们在test文件包下面创建MainTest3测试类文件。

package com.xiaojian.test;

import com.xiaojian.config.MainConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest3 {

    public static void main(String[] args) {

        //1、创建IOC容器
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("IOC容器创建完成");

        System.out.println("IOC容器关闭");
        applicationContext.close();
    }
}

​ 测试结果:

D:\basic\jdk\jdk1.8.0_131\bin\java ...
dog...constructor
dog...@PostConstruct
IOC容器创建完成
IOC容器关闭
dog...@PreDestory

Process finished with exit code 0

​ 如上,为控制台打印的日志文件,可以看出来,在IOC容器初始化之前就已经创建好了bean对象,使用了@PostConstruct注解标注的init初始化方法,在IOC容器关闭的时候使用了@PreDestory注解标注的destory销毁方法。

2.4、BeanPostProcessor-bean的后置处理器(接口)

​ 在Bean初始化进行前后进行一系列的处理操作:

  1. postProcessBeforeInitialization:在初始化之前工作
  2. postProcessAfterInitialization:在初始化之后工作

2.4.1、创建实现类

​ 在bean文件包下面创建MyBeanPostProcessor类文件,实现BeanPostProcessor接口。

package com.xiaojian.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 后置处理器:初始化前后进行处理
 * 将后置处理器加入容器中
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization...before..."+beanName+": "+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization...after..."+beanName+": "+bean);
        return bean;
    }
}

2.4.2、环境配置

​ 此处的配置类我们用MainConfig3配置类,测试类也用MainTest3测试类,同时我们使用Cat、Dog这两个bean对象。

2.4.3、运行测试

​ 运行MainTest3测试类,测试结果如下:

D:\basic\jdk\jdk1.8.0_131\bin\java ...
cat...constructor
postProcessBeforeInitialization...before...cat: com.xiaojian.bean.Cat@71d15f18
cat...afterPropertiesSet
postProcessAfterInitialization...after...cat: com.xiaojian.bean.Cat@71d15f18
dog...constructor
postProcessBeforeInitialization...before...dog: com.xiaojian.bean.Dog@2df32bf7
dog...@PostConstruct
postProcessAfterInitialization...after...dog: com.xiaojian.bean.Dog@2df32bf7
IOC容器创建完成
IOC容器关闭
dog...@PreDestory
cat...destory

Process finished with exit code 0

​ 如上,IOC容器中有两个bean对象,而且在这两个bean对象的初始化前后都有同一个现象。

​ 在Cat这个bean对象初始化之前,容器先运行了MyBeanPostProcessor中的postProcessBeforeInitialization方法;初始化之后,容器运行了MyBeanPostProcessor中的postProcessAfterInitialization方法。(Dog同样)

3.构造(对象创建)

  • 单实例:在容器启动的时候就创建bean对象
  • 多实例:在每次获取的时候创建bean对象

4.初始化具体过程

​ 下面按照顺序的执行:

  • (单例)构造bean

  • BeanPostProcessor.postProcessBeforeInitialization

  • 初始化:对象创建完成,并赋值好,之后调用方法

  • BeanPostProcessor.postProcessAfterInitialization

  • 销毁:单实例—在容器关闭的时候销毁(多实例时候容器部管理bean的销毁)

5、源码分析BeanPostProcessor

BeanPostProcessor遍历得到容器中所有的BeanPostProcessor:挨个执行beforeInitialization,一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization

BeanPostProcessor内部初始化原理:

  • populateBean(beanName,mbd,instanceWrapper)—给bean进行属性赋值

  • InitializeBean的工作顺序:

    • applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);
    • invokeInitMethods(beanName,wrappedBean,mbd)—执行初始化
    • applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);

你可能感兴趣的:(spring注解)