资讯专栏INFORMATION COLUMN

不,你不了解Spring实例化bean的时候做了什么

impig33 / 1862人阅读

摘要:加载的时候构造函数什么时候调用什么时候调用实现了接口的中的和什么时候调用你是否清楚呢如果清楚的话可以直接忽略该篇文章最近来了几个新人,被问了一个和生命周期相关的一个知识点,解决新人的问题后自己再写了一个,目的是为了清晰的描述整个的生命周期。

Spring加载bean的时候构造函数什么时候调用、@PostConstruct什么时候调用、实现了BeanPostProcessor接口的bean中的postProcessAfterInitialization和postProcessBeforeInitialization什么时候调用?你是否清楚呢?如果清楚的话可以直接忽略该篇文章!!!

最近来了几个新人,被问了一个和bean生命周期相关的一个知识点,解决新人的问题后自己再写了一个demo,目的是为了清晰的描述整个bean的生命周期。

注意注意,以下demo有五个类,可能会引起部分人不适,建议可以直接跳到最后看最终总结,或者自己下载源码运行下。
demo地址:https://github.com/wiatingpub...
给出一个demo

首先给出一个实现了BeanFactoryPostProcessor的类,目的是为了比较清晰的看出postProcessBeanFactory接口被调用的时间点。

/**
 * BeanFactoryPostProcessor是bean工厂的处理器
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("【BeanFactoryPostProcessor】实现类postProcessBeanFactory的构造函数");
    }

    // 允许我们在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值,该操作在对应bean的构造函数执行前
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("【BeanFactoryPostProcessor.postProcessBeanFactory】,来自MyBeanFactoryPostProcessor");
        //获取到Spring中所有的beanName
        String[] beanStr = arg0.getBeanDefinitionNames();
        //循环打印
        for (String beanName : beanStr) {
            System.out.print("bean name:" + beanName + ";");
        }

        System.out.println();
    }
}

这里给出一个实现了BeanPostProcessor的类,目的是为了看出postProcessAfterInitialization、postProcessBeforeInitialization调用的时间点。

/**
 * 完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理则要实现接口BeanPostProcessor
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("【MyBeanPostProcessor】BeanPostProcessor实现类的构造函数");
    }

    // 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的业务
    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessAfterInitialization】来自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }

    // 实例化、依赖注入、初始化后完成一些定制的业务
    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {

        if (arg0.getClass() == TestBeanA.class || arg0.getClass() == TestBeanB.class) {
            System.out
                    .println("【BeanPostProcessor.postProcessBeforeInitialization】来自MyBeanPostProcessor,beanName:" + arg1);
        }
        return arg0;
    }
}

这里给出继承了InstantiationAwareBeanPostProcessorAdapter的子类,目的是为了看出postProcessBeforeInitialization、postProcessAfterInitialization、postProcessPropertyValues被调用的时间点。

/**
 * 适配器类,基类是BeanPostProcessor的实现类
 */
@Component
public class MyInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter实现类的构造函数");
    }

    // 接口方法、实例化Bean之前调用
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);

        }
        return bean;
    }

    // 接口方法、实例化Bean之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return bean;
    }

    // 接口方法、设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {

        if (bean.getClass() == TestBeanA.class || bean.getClass() == TestBeanB.class) {
            System.out
                    .println("【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自MyInstantiationAwareBeanPostProcessor,beanName:" + beanName);
        }

        return pvs;
    }

这个就牛逼了,直接交给applicationContext.xml注入并且实现了BeanFactoryAware, BeanNameAware,InitializingBean,DisposableBean四个接口类,目的是为了清晰的看出以下好几个接口被调用的时间点。

public class TestBeanA implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    @PostConstruct
    public void init() {
        System.out.println("【TestBeanA.@PostConstruct】");
    }

    public TestBeanA() {
        System.out.println("【TestBeanA.默认构造器】");
    }

    public TestBeanA(String name) {
        System.out.println("【TestBeanA.带参构造器】");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getPhone() {
        return phone;
    }

    public void setPhone(int phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "TestBeanA [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 这是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware.setBeanFactory】来自TestBeanA");
        this.beanFactory = arg0;
    }

    // 这是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware.setBeanName】来自TestBeanA");
        this.beanName = arg0;
    }

    // 这是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean.afterPropertiesSet】来自TestBeanA");
    }

    // 这是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean.destory】来自TestBeanA");
    }

    // 通过的init-method属性指定的初始化方法
    public void myInit() {
        System.out.println("【TestBeanA.myInit】");
    }

    // 通过的destroy-method属性指定的初始化方法
    public void myDestory() {
        System.out.println("【TestBeanA.destroy-method】");
    }
}

TestBeanB的作用比较简单,为了看出内部数据成员有其他容器Bean的时候Spring是如何加载bean的。

@Component
public class TestBeanB {

    @Autowired
    private TestBeanA testBeanA;

    public TestBeanB() {
        System.out.println("【TestBeanB.默认构造器】");
    }
}

这个是启动类。

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

虽然使用的是SpringBoot,这里还使用xml是为了看看init-method和destroy-method的调用时间。




    
        
    

很长很长的代码算是都给出来了,接下来看下运行后给出的结果

【BeanFactoryPostProcessor】实现类postProcessBeanFactory的构造函数
【BeanFactoryPostProcessor.postProcessBeanFactory】,来自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor实现类的构造函数
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter实现类的构造函数
【TestBeanB.默认构造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【TestBeanA.默认构造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】来自TestBeanA
【BeanFactoryAware.setBeanFactory】来自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】来自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】来自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】来自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanPostProcessor.postProcessBeforeInitialization】来自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】来自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【DiposibleBean.destory】来自TestBeanA
【TestBeanA.destroy-method】

貌似又是一段看完头晕脑胀的恶心代码,不过不方不方,直接进入分析阶段,跟着分析入手就简单多了。

通过结果分析

首先从

【BeanFactoryPostProcessor】实现类postProcessBeanFactory的构造函数
【BeanFactoryPostProcessor.postProcessBeanFactory】,来自MyBeanFactoryPostProcessor
【MyBeanPostProcessor】BeanPostProcessor实现类的构造函数
【MyInstantiationAwareBeanPostProcessor】InstantiationAwareBeanPostProcessorAdapter实现类的构造函数

可以看出执行顺序是:

调用postProcessBeanFactory实现类的构造函数

BeanFactoryPostProcessor是bean工厂的处理器

调用postProcessBeanFactory实现类的postProcessBeanFactory实现函数

postProcessBeanFactory函数允许我们在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值

调用BeanPostProcessor实现类的构造函数

完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理则要实现接口BeanPostProcessor

调用InstantiationAwareBeanPostProcessorAdapter实现类的构造函数

适配器类,基类是BeanPostProcessor的实现类

再从

【TestBeanB.默认构造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

可以看到,此处spring容器先扫描到了TestBeanB,因此调用顺序是

TestBeanB的默认构造器【无参构造器】

调用InstantiationAwareBeanPostProcessorAdapter实现类的postProcessPropertyValues接口

postProcessPropertyValues在接口方法、设置某个属性时调用,通过实验看到实例化一个Bean的时候也会调用该接口方法

之后实例化TestBeanB的时候发现内部注入了TestBeanA,因此Spring转而实例化TestBeanA。

接下来看到的是TestBeanA的实例化过程中调用的顺序

【TestBeanA.默认构造器】
【InstantiationAwareBeanPostProcessorAdapter.postProcessPropertyValues】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【BeanNameAware.setBeanName】来自TestBeanA
【BeanFactoryAware.setBeanFactory】来自TestBeanA
【BeanPostProcessor.postProcessBeforeInitialization】来自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA
【TestBeanA.@PostConstruct】
【InitializingBean.afterPropertiesSet】来自TestBeanA
【TestBeanA.myInit】
【BeanPostProcessor.postProcessAfterInitialization】来自MyBeanPostProcessor,beanName:testBeanA
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanA

调用了TestBeanA的默认构造器

调用InstantiationAwareBeanPostProcessorAdapter实现类的postProcessPropertyValues接口

调用BeanNameAware的setBeanName接口

可以从源码看到TestBeanA实现了接口BeanNameAware

调用BeanFactoryAware的setBeanFactory接口

可以从源码看到TestBeanA实现了接口BeanFactoryAware

调用BeanPostProcessor的postProcessBeforeInitialization接口

调用InstantiationAwareBeanPostProcessorAdapter的postProcessBeforeInitialization接口

调用TestBeanA中注解了@PostConstruct的函数

调用了InitializingBean的afterPropertiesSet接口

可以从源码看到TestBeanA实现了接口InitializingBean

调用了TestBeanA的myInit接口

可以看到该init-method接口是在applicationContext中init-method配置上的

调用BeanPostProcessor实现类的postProcessAfterInitialization接口

调用InstantiationAwareBeanPostProcessorAdapter子类的postProcessAfterInitialization接口

等TestBeanA实例化结束后,则继续TestBeanB的实例化路程

【BeanPostProcessor.postProcessBeforeInitialization】来自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessBeforeInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB
【BeanPostProcessor.postProcessAfterInitialization】来自MyBeanPostProcessor,beanName:testBeanB
【InstantiationAwareBeanPostProcessorAdapter.postProcessAfterInitialization】来自MyInstantiationAwareBeanPostProcessor,beanName:testBeanB

调用BeanPostProcessor实现类的postProcessBeforeInitialization接口

调用InstantiationAwareBeanPostProcessorAdapter子类的postProcessBeforeInitialization接口

调用BeanPostProcessor实现类的postProcessAfterInitialization接口

调用InstantiationAwareBeanPostProcessorAdapter子类的postProcessAfterInitialization接口

最后

【DiposibleBean.destory】来自TestBeanA
【TestBeanA.destroy-method】

调用DiposibleBean实现类的destory接口

TestBeanA实现了DiposibleBean接口,实现了destroy接口

调用TestBeanA的myDestory函数

可以看到该myDestory接口是在applicationContext中destroy-method配置上的。
最终总结

【超重点,面试回答模板,老牛逼了】

如果有bean实现了BeanFactoryPostProcessor接口类,则会实例化该bean,并且调用默认构造器,然后调用postProcessBeanFactory接口

如果有bean实现了BeanPostProcessor接口类,则会先实例化该bean,同样调用默认构造器

如果有bean继承了InstantiationAwareBeanPostProcessorAdapter类,则会先实例化该bean,同样调用默认构造器

之后真正进入一个bean的生命周期过程

先调用bean的默认构造函数

如果有bean继承了InstantiationAwareBeanPostProcessorAdapter类,此刻会调用postProcessPropertyValues函数

如果这个bean已经实现了BeanNameAware接口,会调用它实现的setBeanName方法,此处传递的就是applicationContext.xml配置文件中Bean的id值

如果这个bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory,传递的是Spring工厂自身

如果存在其他bean实现了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;

如果存在其他bean继承了InstantiationAwareBeanPostProcessorAdapter类,则会调用postProcessBeforeInitialization接口

如果这个bean中有函数加了@PostConstruct注解,则该函数会在此刻被调用

如果这个bean实现了InitializingBean接口重写了afterPropertiesSet方法,该方法会在此刻被调用

如果这个bean在Spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法。

如果存在其他bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法

如果存在其他bean继承了InstantiationAwareBeanPostProcessorAdapter类,则会调用postProcessAfterInitialization接口

走到这一步以后就可以应用这个Bean了,而这个Bean是一个Singleton的,虽然在Spring配置文件中也可以配置非Singleton,这里不做赘述。

走入销毁阶段

当bean不再需要时,会经过清理阶段,如果这个bean实现了DisposableBean接口,会调用其实现的destroy()方法;

如果这个bean的applicationContext.xml配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

Java源码分析、go语言应用、微服务,更多干货欢迎关注公众号:

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74697.html

相关文章

  • 面试被问烂 Spring IOC(求求你别再问了)

    摘要:例如资源的获取,支持多种消息例如的支持,对多了工具级别的支持等待。最上面的知道吧我就不讲了。生命周期事件回调等。他支持不同信息源头,支持工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。 广义的 IOC IoC(Inversion of Control) 控制反转,即不用打电话过来,我们会打给你。 两种实现: 依赖查找(DL)和依赖注入(DI)。 IOC 和...

    denson 评论0 收藏0
  • Spring IOC 容器源码分析系列文章导读

    摘要:本文是容器源码分析系列文章的第一篇文章,将会着重介绍的一些使用方法和特性,为后续的源码分析文章做铺垫。我们可以通过这两个别名获取到这个实例,比如下面的测试代码测试结果如下本小节,我们来了解一下这个特性。 1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本。经过十几年的迭代,现在的 Spring 框架已经非常成熟了...

    NSFish 评论0 收藏0
  • Spring IOC 容器源码分析 - 循环依赖解决办法

    摘要:实例化时,发现又依赖于。一些缓存的介绍在进行源码分析前,我们先来看一组缓存的定义。可是看完源码后,我们似乎仍然不知道这些源码是如何解决循环依赖问题的。 1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的。在本篇文章中,我会首先向大家介绍一下什么是循环依赖。然后,进入源码分析阶段。为了更好的说明 Spring 解决循环依赖的办法,我将会从获取 bean 的方法getB...

    aikin 评论0 收藏0
  • 零基础带你看Spring源码——IOC控制反转

    摘要:依赖注入是向某个类或方法注入一个值,其中所用到的原理就是控制反转。但发现更多时间是在调和的源码。里面就是从中取出这个,完成控制反转的。控制反转的优点最后来以我个人观点谈谈控制反转的优点吧。控制反转为了降低项目耦合,提高延伸性。 本章开始来学习下Spring的源码,看看Spring框架最核心、最常用的功能是怎么实现的。网上介绍Spring,说源码的文章,大多数都是生搬硬推,都是直接看来的...

    wing324 评论0 收藏0
  • 仿照 Spring 实现简单 IOC 和 AOP - 下篇

    摘要:在上文中,我实现了一个很简单的和容器。比如,我们所熟悉的就是在这里将切面逻辑织入相关中的。初始化的工作算是结束了,此时处于就绪状态,等待外部程序的调用。其中动态代理只能代理实现了接口的对象,而动态代理则无此限制。 1. 背景 本文承接上文,来继续说说 IOC 和 AOP 的仿写。在上文中,我实现了一个很简单的 IOC 和 AOP 容器。上文实现的 IOC 和 AOP 功能很单一,且 I...

    AlexTuan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<