浅尝Spring注解开发_Bean生命周期及执行过程

Spring注解开发_Bean生命周期及执行过程

浅尝Spring注解开发,基于Spring 4.3.12
包含Bean生命周期、自定义初始化方法、Debug BeanPostProcessor执行过程及在Spring底层中的应用

浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
浅尝Spring注解开发_Bean生命周期及执行过程
浅尝Spring注解开发_AOP原理及完整过程分析(源码)
浅尝Spring注解开发_声明式事务及原理
浅尝Spring注解开发_简单理解BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor、ApplicationListener
Spring注解开发_Spring容器创建概述
浅尝Spring注解开发_Servlet3.0与SpringMVC

Bean生命周期

了解Bean的生命周期,就可以在Bean声明周期的不同阶段进行自定义的操作,满足更复杂的需求。简单的将Bean生命周期分为三个阶段:Bean创建、初始化、销毁

  • 对象创建:单实例在容器启动的时候创建对象,多实例在每次获取的时候创建对象
  • 初始化之前:BeanPostProcessor.postProcessBeforeInitialization()
  • 初始化:对象创建完成,并赋值好,调用初始化方法
  • 初始化之后:BeanPostProcessor.postProcessAfterInitialization()
  • [容器创建完成]
  • 销毁:单实例在容器关闭的时候销毁,多实例 容器不会管理这个bean,容器不会调用销毁方法*
    现在可以通过下面方法在初始化和销毁时
    自定义初始化方法**来干涉Bean创建过程。

  • @Bean()注解参数

  • InitializingBean、DisposableBean接口
  • @PostConstruct、@PreDestroy注解
  • BeanPostProcessor接口

1.@Bean生命周期

通过@Bean指定init-method和destroy-method的初始化方法

  • 先自定义Bean初始化和销毁方法
@Component
public class Car {

    public Car(){
        System.out.println("car constructor...");
    }
    //现在只是普通方法
    public void init(){
        System.out.println("car ... init...");
    }
    //现在只是普通方法
    public void detory(){
        System.out.println("car ... destory...");
    }

}
  • 配置进容器
  • 通过@Bean注解,在@Bean注册进容器时指定自定义方法
@Configuration
public class MainConfigOfLifeCycle {

    //@Scope("prototype")多实例,不管销毁
    //指定用于初始化和销毁的方法
    @Bean(initMethod="init",destroyMethod="destory")
    public Car car(){
        return new Car();
    }

}
  • 测试
public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }

}

输出

//先创建对象
car constructor...

//再自定义初始化方法
car ... init...

//创建完成
容器创建完成...

//关闭时自定义销毁方法
car ... destory...

2.InitializingBean,DisposableBean生命周期

接口,需实现,通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);

  • 实现接口,自定义初始化Bean
public class Cat implements InitializingBean,DisposableBean {

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

    //定义销毁逻辑
    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...destroy...");
    }

    //定义初始化逻辑
    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...afterPropertiesSet...");
    }

}
  • 配置进容器
  • 在@Configuration配置类中使用@Bean
  • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
//配置组件
@Component
public class Cat implements InitializingBean,DisposableBean {
    //...

}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
    //...

}
  • 测试
public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }
}

输出

//注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外
(猫)cat constructor...

(猫)cat...afterPropertiesSet...

(车)car constructor...

(车)car ... init...

//创建完成
 容器创建完成...

//关闭时销毁
(车)car ... destory...

(猫)cat...destroy...

3.@PostConstruct生命周期

可以使用JSR250;

  • @PostConstruct:在bean创建完成并且属性赋值完成之后,来执行初始化方法
  • @PreDestroy:在容器销毁bean之前通知我们进行清理工作
  • 标注注解,自定义初始化Bean
public class Dog {

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

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

    //容器移除对象之前
    @PreDestroy
    public void detory(){
        System.out.println("Dog....@PreDestroy...");
    }
}
  • 配置进容器
  • 在@Configuration配置类中使用@Bean
  • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
@Component
public class Dog {
    //...

}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
    //...

}
  • 测试
public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }

}

输出

//注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外
(猫)cat constructor...

(猫)cat...afterPropertiesSet...

(狗)dog constructor...

(狗)Dog....@PostConstruct...

(车)car constructor...

(车)car ... init...

//创建完成
容器创建完成...

//关闭时销毁
(车)car ... destory...

(狗)Dog....@PreDestroy...

(猫)cat...destroy...

4.BeanPostProcessor

postProcessBeforeInitialization:在创建Bean实例之后,在自定义初始化之前进行调用
postProcessAfterInitialization:在自定义初始化之后进行调用

BeanPostProcessor接口:bean的后置处理器,需实现,在bean初始化前后进行一些处理工作

  • postProcessBeforeInitialization:在 (自定义初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定义初始化方法)初始化之前工作 (创建Bean实例之后,在自定义初始化之前)
  • postProcessAfterInitialization:在(自定义)初始化之后工作
  • 实现后置处理器接口
public class MyBeanPostProcessor implements BeanPostProcessor {

    //初始化前置方法
    //bean:新创建的实例,还未初始化
    //beanName:未初始化的Bean名字
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }
    //初始化后置方法
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }

}
  • 配置进容器
  • 在@Configuration配置类中使用@Bean
  • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    //...

}
//扫描进容器
@ComponentScan("com.xxx.bean")
@Configuration
public class MainConfigOfLifeCycle {
    //...

}
  • 测试
  • 这次没有新增的Bean,只配置了一个后置处理器,
  • 这个后置处理器会对容器中的Bean起作用,包括上面三种自定义初始化Bean
public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }

}

输出

//对于每一个Bean都要执行一遍
//1.创建
//2.BeanPostProcessor.postProcessBeforeInitialization()
//3.初始化:对象创建完成,并赋值好,调用初始化方法...

//4.BeanPostProcessor.postProcessAfterInitialization()
//5.销毁

//以其中一个Bean为例:
//构造对象
cat constructor...

//初始化之前
postProcessBeforeInitialization...cat=>com.xxx.bean.Cat@7d68ef40
//使用InitializingBean自定义初始化逻辑
cat...afterPropertiesSet...

//初始化之后
postProcessAfterInitialization...cat=>com.xxx.bean.Cat@7d68ef40
//创建完成
容器创建完成...

//关闭时销毁
cat ... destroy...

⭐BeanPostProcessor原理

bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanPostProcessor都通过BeanPostProcessor实现
详细视频 https://www.bilibili.com/video/BV1gW411W7wy?p=16

主要方法

populateBean(beanName, mbd, instanceWrapper):给bean进行属性赋值
initializeBean:初始化Bean
{
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);初始化前应用后置处理器
    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);初始化后应用后置处理器
}
遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
一但返回null,跳出for循环

执行过程

了解BeanPostProcessor的执行过程,从AnnotationConfigApplicationContext开始Debug

public class IOCTest_LifeCycle {

    @Test
    public void test01(){
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //applicationContext.getBean("car");
        //关闭容器
        applicationContext.close();
    }
}
  1. 先从创建ioc容器开始,进入 AnnotationConfigApplicationContext()构造方法,执行里面的 refresh()方法刷新容器
  2. refresh()方法里面有一个 finishBeanFactoryInitialization(beanFactory)初始化所有剩余的单实例对象,进入这个方法
  3. 这个方法最后一步有一个 beanFactory.preInstantiateSingletons()初始化所有单实例Bean,进入这个方法
  4. 触发所有非惰性单例bean的初始化
  5. 里面调用 getBean(beanName)
  6. 进入 getBean(beanName)里面再调用 doGetBean(name,null,null,false)
  7. 进入 doGetBean(name,null,null,false)里面有 getSingleton(beanName,new ObjectFactory(){singletonFactory.getObject()})通过匿名内部类调用 getObject()
  8. 此时通过匿名类 getObject()进入下一个调用栈 AbstractBeanFactory$1.getObject(),如果是单例,调用 createBean(beanName,mbd,args)
  9. 进入 createBean(beanName,mbd,args)调用 doCreateBean(beanName,mbd,args)创建一个实例,过程如下
  10. 进入 doCreateBean(beanName,mbd,args),里面调用一个 initializeBean(beanName,exposedObject,mbd)初始化方法,这个方法里面就是调用的后置处理器
  11. 在这个方法上面有 populateBean(beanName,mbd,instanceWrapper)方法,这个方法为Bean属性赋值
  12. 进入 initializeBean(beanName,exposedObject,mbd),下面有一个 invokeInitMethods(beanName,wrappedBean,mbd)执行初始化方法(就是上面的自定义初始化InitializingBean[afterPropertiesSet]、init-method)
  13. invokeInitMethods(beanName,wrappedBean,mbd)[在初始化之前应用 BeanPost 处理器]上面有一个 applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)下面有一个 applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)[在初始化之后应用 BeanPost 处理器],作用是在初始化之前应用所有的 BeanPostProcessors在初始化之后应用所有的 BeanPostProcessors
  14. 进入 applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
  15. 里面有 getBeanPostProcessors()找到所有 BeanPostProcessors遍历,包括Spring系统的 BeanPostProcessorApplicationContextAwareProcessorConfigurationClassPostProcessor等,然后才是自定义的 MyBeanPostProcessor,依次执行 beanProcessor.postProcessBeforeInitialization()
  16. 如果有执行返回null,就结束遍历,返回null,后面的处理器就不执行了(不应用后续的 BeanPostProcessors了)

调用栈

浅尝Spring注解开发_Bean生命周期及执行过程
浅尝Spring注解开发_Bean生命周期及执行过程
浅尝Spring注解开发_Bean生命周期及执行过程

完整流程

Spring底层对 BeanPostProcessor 的使用;

浅尝Spring注解开发_Bean生命周期及执行过程
  1. 由上图可以看到,Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization
  2. 前者在实例化及依赖注入完成后、在任何初始化代码(比如配置文件中的init-method)调用之前调用;后者在初始化代码调用之后调用。

⭐BeanPostProcessor在Spring底层的使用

许多注解底层都是基于BeanPostProcessor

BeanPostProcessor接口实现类

浅尝Spring注解开发_Bean生命周期及执行过程

向组件中注入IoC容器

在Bean创建过程中,初始化之前,判断是否实现了某Aware接口,如果实现了,就向Bean中注入ApplicationContext容器

  • 向Bean中注入IoC容器
  • 实现ApplicationContextAware接口,声明属性,赋值,就可以在组件中使用Ioc容器
@Component
public class Dog implements ApplicationContextAware {

    //声明IoC容器
    private ApplicationContext applicationContext;

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

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

    //容器移除对象之前
    @PreDestroy
    public void detory(){
        System.out.println("Dog....@PreDestroy...");
    }

    //把applicationContext IoC容器赋值给属性
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // TODO Auto-generated method stub
        this.applicationContext = applicationContext;
    }
}
  • 原理是通过 ApplicationContextAwareProcessor实现
    浅尝Spring注解开发_Bean生命周期及执行过程
  • postProcessBeforeInitialization()方法中
    1. 在Bean初始化之前,判断Bean是否实现了 ApplicationContextAware接口,或其他Aware接口
    2. 如果实现了,就调用 invokeAwareInterfaces(bean)给Bean注入值
    3. 判断Bean是什么类型Aware,将Bean转成对应类型调用 ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext)注入IoC容器
    4. 于是就到了上面实现的接口的未实现方法中

数据校验

  • BeanValidationPostProcessor也实现了 BeanPostProcessor接口
  • 在Bean创建完赋值后,同样调用 postProcessBeforeInitialization()方法,进行数据校验
  • postProcessBeforeInitialization(){doValidate(bean)}
  • postProcessAfterInitialization(){doValidate(bean)}

自定义初始化注解

  • Bean初始化有一种方法是使用 @PostConstruct注解,也是通过 BeanPostProcessor实现
  • InitDestroyAnnotationBeanPostProcessor处理 @PostConstruct@PreDestroy注解
  • postProcessBeforeInitialization()中找到Bean的生命周期注解所标注的方法,如 initMethods、destroyMethods
  • 找到之后就执行注解标注的初始化方法 metatata.invokeInitMethods(bean,beanName)element.invoke(target),利用反射执行。

自动注入注解@Autowired

  • 为什么@Autowired能够自动注入值,是通过这个 AutowiredAnnotationBeanPostProcessor实现 BeanPostProcessors接口
  • 在对象创建完之后,处理标注 @Autowired标注的所有属性进行注入值

Original: https://www.cnblogs.com/wei-ran/p/16207148.html
Author: 蔚然丶丶
Title: 浅尝Spring注解开发_Bean生命周期及执行过程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/569870/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • dubbo源码分析2(jdk原生spi机制)

    jdk中有一个spi的机制,可能很多人听都没听过,我以前也没有听说过,我擦(╯—﹏—)╯(┷━━━┷ 因为一个接口可以有很多个不同的实现类嘛,而spi机制的作用就是使用配置文件可以…

    Java 2023年6月6日
    0111
  • (转)localStorage使用总结 localStorage sessionStorage

    转:https://www.cnblogs.com/st-leslie/p/5617130.html 一、什么是localStorage、sessionStorage 在HTML5…

    Java 2023年5月30日
    068
  • Java I/O 流之对象流中的序列化和反序列化

    一、概念 当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过 http 协议发送字符串信息;我们也可以…

    Java 2023年6月13日
    073
  • Java抓取网页图片并下载到本地(HTTP)

    直接上代码: package com.clzhang.sample.net; import java.io.File; import java.io.FileOutputStrea…

    Java 2023年5月29日
    075
  • Error:(8,46) java: 程序包com.xxx.local不存在

    项目在进行maven编译的时候出现 “Error:(8,46) java: 程序包com.xxx.local不存在” 问题,但是从idea中看又存在,没有问…

    Java 2023年5月29日
    076
  • MQTT 协议基本介绍

    MQTT 全称为 Message Queuing Telemetry Transport(消息队列遥测传输)是一种基于发布/订阅范式的”轻量级”消息协议,由…

    Java 2023年5月30日
    089
  • 一文带你搞懂 JWT 常见概念 & 优缺点

    在 JWT 基本概念详解这篇文章中,我介绍了: 什么是 JWT? JWT 由哪些部分组成? 如何基于 JWT 进行身份验证? JWT 如何防止 Token 被篡改? 如何加强 JW…

    Java 2023年6月9日
    082
  • 数组

    是一种用于存储 多个相同数据类型的存储模型 静态初始化 int [] arr = {1,8,12,3,5,9}; int arr2 [] = {1,8,12,3,5,9};//创建…

    Java 2023年6月8日
    084
  • 整理的Java List Set Map是否有序,元素是否允许重复

    整理的Java List Set Map是否有序,元素是否允许重复的说明,如下图: Original: https://www.cnblogs.com/muyuge/p/61524…

    Java 2023年5月29日
    067
  • Linux安装SVN

    1、安装 yum install subversion 如果想采用下载压缩包解压安装可参阅: https://blog.csdn.net/qq_23167527/article/d…

    Java 2023年6月8日
    072
  • k8s 新版本 部署 Ingress-nginx controller

    k8s 新版本 部署 Ingress-nginx controller 本篇主要记录一下 k8s 新版本 1.23.5 中如何搭建 ingress controller 以及里面的…

    Java 2023年6月9日
    065
  • uni模板

    html;gutter:true; export default { components:{ }, data () { return {} }, onLoad () {}, on…

    Java 2023年5月29日
    075
  • CAS底层原理与ABA问题

    CAS定义 CAS(Compare And Swap)是一种无锁算法。CAS算法是乐观锁的一种实现。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当预期值A和内存值V…

    Java 2023年6月7日
    071
  • Spring源码分析

    https://blog.csdn.net/u010013573/article/details/86547687 Original: https://www.cnblogs.co…

    Java 2023年5月30日
    081
  • Spring Boot下拦截器与过滤器

    在讲Spring boot之前,我们先了解一下过滤器和拦截器。这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。在分析两者的区别之前,我们先理解一下AOP的概念,A…

    Java 2023年5月30日
    070
  • Cnblogs-Theme-SimpleMemory 定制分享

    配置文件 这是我个人参考官方的配置指南根据自己的需求配置的, 部分功能添加后效果不理想故而注释 用户图像横幅图片,推荐下载保存到本地然后上传到 Github 再用此连接。 防止日后…

    Java 2023年6月5日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球