Spring底层分析--4.Bean的生命周期,后处理器,模板方法

一.Bean生命周期

  其定义为:从对象的创建到销毁的过程。而Spring中的一个Bean从开始到结束经历很多过程,但总体可以分为六个阶段:Bean定义、实例化、属性赋值、初始化、生存期、销毁

二.创建一个类,注解为@Component

@Component
public class BeanLifeCtrl {

    private final static Logger log =  LoggerFactory.getLogger(BeanLifeCtrl.class);

    public BeanLifeCtrl(){
      log.info("执行了构造方法");
    }

    @Autowired
    public void getName(@Value("java_home")String java_home){
        log.info("依赖注入:"+java_home);
    }

    @PostConstruct
    public void postConstruct(){
        log.info("构造后处理!");
    }

    @PreDestroy
    public void beforeDestroy(){
        log.info("销毁前处理");
    }

}

然后运行springboot

2023-09-18 09:51:15.480  INFO 17872 --- [           main] com.jjh.BeanLifeApplication              : Starting BeanLifeApplication using Java 11.0.14 on LAPTOP-UR1MH949 with PID 17872 (E:\cloud-project\BeanLife\target\classes started by JJH in E:\cloud-project\SpringIoc)
2023-09-18 09:51:15.482  INFO 17872 --- [           main] com.jjh.BeanLifeApplication              : No active profile set, falling back to 1 default profile: "default"
2023-09-18 09:51:15.693  INFO 17872 --- [           main] com.jjh.component.BeanLifeCtrl           : 执行了构造方法
2023-09-18 09:51:15.695  INFO 17872 --- [           main] com.jjh.component.BeanLifeCtrl           : 依赖注入:java_home
2023-09-18 09:51:15.696  INFO 17872 --- [           main] com.jjh.component.BeanLifeCtrl           : 构造后处理!
2023-09-18 09:51:15.742  INFO 17872 --- [           main] com.jjh.BeanLifeApplication              : Started BeanLifeApplication in 0.444 seconds (JVM running for 1.274)
2023-09-18 09:51:15.745  INFO 17872 --- [           main] com.jjh.component.BeanLifeCtrl           : 销毁前处理

三.自定义bean后处理器

这两个接口都实现了BeanPostProcessor接口

@Component
public class MYBeanPostPoccesser implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
   private final static Logger log = LoggerFactory.getLogger(MYBeanPostPoccesser.class);
    @Override
    public void postProcessBeforeDestruction(Object o, String beanName) throws BeansException {
        if("beanLifeCtrl".equals(beanName)){
            log.info("在销毁前处理,如@PreDestory");
        }

    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if("beanLifeCtrl".equals(beanName)){
            log.info("实例化之前执行,这里的bean会替换初始的bean");
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if("beanLifeCtrl".equals(beanName)){
            log.info("在实例化之后处理,如果返回false,则跳过依赖注入阶段");
        }
        return true;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("beanLifeCtrl".equals(beanName)){
            log.info("实例化之后处理,这里的bean会替换初始的bean");
        }
        return null;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if("beanLifeCtrl".equals(beanName)){
            log.info("在依赖注入阶段执行,如@Autowired,@Resource");
        }
        return null;
    }

}

我们在运行查看结果:

2023-09-18 10:24:03.251  INFO 19208 --- [           main] com.jjh.component.MYBeanPostPoccesser    : 实例化之前执行,这里的bean会替换初始的bean
2023-09-18 10:24:03.252  INFO 19208 --- [           main] com.jjh.component.BeanLifeCtrl           : 执行了构造方法
2023-09-18 10:24:03.253  INFO 19208 --- [           main] com.jjh.component.MYBeanPostPoccesser    : 在实例化之后处理,如果返回false,则跳过依赖注入阶段
2023-09-18 10:24:03.253  INFO 19208 --- [           main] com.jjh.component.MYBeanPostPoccesser    : 在依赖注入阶段执行,如@Autowired,@Resource
2023-09-18 10:24:03.255  INFO 19208 --- [           main] com.jjh.component.BeanLifeCtrl           : 依赖注入:java_home
2023-09-18 10:24:03.256  INFO 19208 --- [           main] com.jjh.component.BeanLifeCtrl           : 构造后处理!
2023-09-18 10:24:03.256  INFO 19208 --- [           main] com.jjh.component.MYBeanPostPoccesser    : 实例化之后处理,这里的bean会替换初始的bean
2023-09-18 10:24:03.328  INFO 19208 --- [           main] com.jjh.BeanLifeApplication              : Started BeanLifeApplication in 0.475 seconds (JVM running for 1.346)
2023-09-18 10:24:03.332  INFO 19208 --- [           main] com.jjh.component.MYBeanPostPoccesser    : 在销毁前处理,如@PreDestory
2023-09-18 10:24:03.332  INFO 19208 --- [           main] com.jjh.component.BeanLifeCtrl           : 销毁前处理

进程已结束,退出代码0

可以很清晰的看到执行顺序:

实例化之前处理器->构造方法->实例化之后处理器(判断是否跳过依赖注入)->依赖注入处理器->依赖注入->构造后处理->实例化之后处理器->销毁前处理器->销毁前处理

四.模板设计模式

我们可以把固定不变的流程设计为模板,其中动态变化的方法,我们可以通过接口,给它添加进去,在需要执行的方调用不同的实现方法

1,定义MyBeanPostPoccessor接口

interface MyBeanPostProcessor{
    //依赖注入
    void inject();
}

2.创建MyBeanFactory类

class MyBeanFactory{

    private List<MyBeanPostProcessor> postProcessors = new ArrayList<>();


    public Object getBean(){
        Object bean = new Object();
        System.out.println("构造方法");

        System.out.println("依赖注入");
         postProcessors.forEach(MyBeanPostProcessor::inject);
        System.out.println("初始化");
        return bean;
    }

    public void addProcessor(MyBeanPostProcessor postProcessor){
        postProcessors.add(postProcessor);
    }
}

我们在依赖注入之后执行需要的方法

3.我们给它添加这个后处理器,实现方法


       MyBeanFactory beanFactory = new MyBeanFactory();
       beanFactory.addProcessor(() -> System.out.println("@Autowired注解注入"));
       beanFactory.addProcessor(()-> System.out.println("@Resource注解注入"));

       beanFactory.getBean();

运行代码,查看结果:

构造方法
依赖注入
@Autowired注解注入
@Resource注解注入
初始化

可以看到,我们添加的方法执行了

五.Bean的后处理器

1.准备

我们知道,spring提供了很多注解,对应bean每个阶段的生命周期,那么我们来分析一下后处理器的执行流程

创建Bean1类

@Component
public class Bean1 {

    private final static Logger log =  LoggerFactory.getLogger(Bean1.class);
    
    private Bean2 bean2;

    @Resource
    public void setBean2(Bean2 bean2){
        this.bean2 = bean2;
        log.info("@Resource生效....");
    }

    public Bean2 getBean2() {
        return bean2;
    }

    public Bean1(){
        log.info("执行构造方法....");
    }

    @Autowired
    public void getName(@Value("${java_home}")String home){
        log.info("@Autowired值注入:{}",home);
    }



    @PostConstruct
    public void postConstruct(){
        log.info("@PostConstruct生效...构造后处理");
    }


    @PreDestroy
    public void preDestroy(){
        log.info("@PreDestroy生效...销毁前处理");
    }


}

创建Bean2类

@Component
public class Bean2 {
}

使用GenericApplicationContext作为容器,因为它比较干净,没有自己添加后处理器,方便测试

       GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean1", Bean1.class);
       //实例化bean
       context.refresh();
       //关闭bean
        context.close();

 运行查看结果:

11:30:40.165 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@28ac3dc3
11:30:40.192 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
11:30:40.204 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
11:30:40.204 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:30:40.230 [main] DEBUG org.springframework.context.support.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@28ac3dc3, started on Mon Sep 18 11:30:40 CST 2023

发现只有构造方法被执行了,注解的方法并没有被执行,下面我们给它添加后处理器

2.添加AutowiredAnnotationBeanPostProcessor后处理器

它可以解析@Autowired,@Value

注意:我们需要在添加它之前设置AutowireCanidateResolver()为ContextAnnotationAutowiredCandidateResolver()解析器,否则无法解析Stirng的值

 context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  context.registerBean(AutowiredAnnotationBeanPostProcessor.class);

查看结果;

11:35:13.221 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:35:13.280 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bean1': Unsatisfied dependency expressed through method 'getName' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Value(value="${java_home}")}

发现解析了@Autowired

3.添加CommonAnnotationBeanPostProcessor后处理器

它可以解析@Resource,@PostConstuct,@Predestory

    context.registerBean(CommonAnnotationBeanPostProcessor.class);

查看结果:

11:37:17.371 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
11:37:17.424 [main] INFO com.jjh.component.Bean1 - @Resource生效....
11:37:17.426 [main] WARN org.springframework.context.support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bean1': Unsatisfied dependency expressed through method 'getName' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Value(value="${java_home}")}

发现@Resource生效

4.Springboot中的@ConfigurationProperties注解

spirngboot可以通过该注解读取配置文件里的信息

(1)准备application.yml文件


java:
  home: E:\java
  version: 1.8

(2)创建Bean3类

@Component
@ConfigurationProperties(prefix = "java")
public class Bean3 {


    private String home;

    private String version;

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return "Bean3{" +
                "home='" + home + '\'' +
                ", version='" + version + '\'' +
                '}';
    }
}

(3)注册这个bean3,并读取观察信息

 context.registerBean("bean3", Bean3.class);



  //实例化bean
       context.refresh();
       //关闭bean

        System.out.println(context.getBean("bean3"));

查看结果:

15:08:51.880 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
Bean3{home='null', version='null'}

发现并没有解析@ConfigurationProperties

我们添加ConfigurationPropertiesBindingPostProcessor处理器

 //解析spirngboot中的@ConfigurationPerporties
        ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());

再次运行,查看:

15:16:11.916 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
Bean3{home='E:\Java', version='11.0.14'}

发现成功的解析了该注解

六.AutowiredAnnotationBeanPostProcessor后处理器工作流程

我们知道它可以解析@Autowired和@Value注解,下面让我们看一下它的工作流程:

public class DigInAutowiredProcessorTest {
    public static void main(String[] args) throws Throwable {

        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        beanFactory.registerSingleton("bean2",new Bean2());
        //beanFactory.registerSingleton("bean1",new Bean1());

        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        //设置${}解析器
       beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders);

        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();

        processor.setBeanFactory(beanFactory);


        Bean1 bean1 = new Bean1();

       processor.postProcessProperties(null,bean1,"bean1");


        System.out.println(bean1);

查看一下运行结果:

15:54:03.689 [main] INFO com.jjh.component.Bean1 - 执行构造方法....
15:54:03.777 [main] DEBUG org.springframework.core.env.SystemEnvironmentPropertySource - PropertySource 'systemEnvironment' does not contain property 'java_home', but found equivalent 'JAVA_HOME'
15:54:03.777 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'java_home' in PropertySource 'systemEnvironment' with value of type String
15:54:03.778 [main] INFO com.jjh.component.Bean1 - @Autowired值注入:E:\java
com.jjh.component.Bean1@38d8f54a

最重要的方法是

processor.postProcessProperties(null,bean1,"bean1");

这个方法就是在依赖注入时注入值的,

我们看一下它的源码:

    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);

        try {
            metadata.inject(bean, beanName, pvs);
            return pvs;
        } catch (BeanCreationException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
        }
    }

这里的findAutowiringMetadata()方法是查找类的成员变量和方法上是否带上了@Autowired注解,

找到之后返回InjectionMetadata对象,然后调用metada.inject()方法来实现依赖注入,该方法需要三个参数,哪个bean,bean的名称,null

下面我们使用反射的方法来调用一下这个inject()方法:

        //利用反射获取方法
        Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
       //调用该方法
        findAutowiringMetadata.setAccessible(true);
        //获取到metadata
        InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor,"bean1",Bean1.class,null);
         //调用inject方法注入依赖
        metadata.inject(bean1,"bean1",null);

所有核心流程是:

1.先查找哪个成员变量和方法上注解了@Autowired

2.调用inject()方法对bean进行依赖注入

那么它是如何找到要注入的bean的呢?

我们先来看这三个:

    @Autowired
    private Bean4 bean4;

    @Autowired
    public void setBean2(Bean2 bean2){
        this.bean2 = bean2;
        log.info("@Autowired生效....");
    }


    @Autowired
    public void setName(@Value("${java_home}")String home){
        log.info("@Autowired值注入:{}",home);
    }

这三个都需要找到要注入的bean,

        //在成员变量上注入
        Field bean4 = Bean1.class.getDeclaredField("bean4");
        DependencyDescriptor descriptor1 = new DependencyDescriptor(bean4,false);
        Object o = beanFactory.doResolveDependency(descriptor1, null, null, null);
        System.out.println(o);

        //在方法上注入
        Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
        DependencyDescriptor descriptor2 =
                new DependencyDescriptor(new MethodParameter(setBean2,0),false);
        Object o1 = beanFactory.doResolveDependency(descriptor2, null, null, null);
        System.out.println(o1);

        //@Value注入
        Method setHome = Bean1.class.getDeclaredMethod("setName", String.class);
        DependencyDescriptor descriptor3 =
                new DependencyDescriptor(new MethodParameter(setHome,0),false);
        Object o2 = beanFactory.doResolveDependency(descriptor3, null, null, null);
        System.out.println(o2);

主要是DependencyDescriptor类,

基本是就是先通过反射拿到被注解了的成员变量和方法,然后变量可以获取这个属性的类型,

方法可以根据他的参数找到类型,从而从容器中获取bean然后注入依赖

然后通过beanFactory.doResolveDependency()方法,来获取这个bean

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值