Bean生命周期

Spring需要使用的组件配置pom.xml

1.Bean声明周期概述

Bean的生命周期:指bean“创建-----初始化----销毁”的过程。
Bean的生命周期是由容器进行管理的。
我们可以自定义 Bean初始化和销毁方法: 容器在Bean进行到当前生命周期的时候, 来调用自定义的初始化和销毁方法

2.Bean初始化和销毁的三种方式

2.1 指定初始化和销毁方法

在配置类里通过@Bean(initMethod="init", destroyMethod="destroy")指定
需要注册的Bean:Bike.java

public class Bike {
    public Bike(){
        System.out.println("Bike constructor..............");
    }
    public void init(){
        System.out.println("Bike .....init.....");
    }
    public void destory(){
        System.out.println("Bike.....destory");
    }
}

配置类中指定Bike的init和destory方法

    //@Scope("prototype")
    @Bean(initMethod="init", destroyMethod="destory")
    public Bike bike(){
        return new Bike();
    }

测试类Ch7Test.java

public class Ch7Test {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch7MainConfigOfLifeCycle.class);

        System.out.println("IOC容器创建完成........");
        app.close();
    }
}

结果如下:

给容器中添加person.......
Bike constructor..............
Bike .....init.....
IOC容器创建完成........
Bike.....destory

2.2 让Bean实现 InitializingBean 和 DisposableBean接口

  • InitializingBean(定义初始化逻辑,可点进去看此类):afterPropertiesSet()方法:当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法
  • DisposableBean(定义销毁逻辑,可点进去看此类):destory()方法,当bean销毁时,会把单实例bean进行销毁

实现 InitializingBean 和 DisposableBean接口的Train.java

@Component
public class Train implements InitializingBean, DisposableBean {

    public Train(){
        System.out.println("Train......constructor............");
    }
    //当我们bean销毁时,调用此方法
    @Override
    public void destroy() throws Exception {
        System.out.println("Train......destory......");
        //logger.error
    }
    //当我们的bean属性赋值和初始化完成时调用
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Train.......afterPropertiesSet()...");
    }
}

配置类

@ComponentScan("com.wangzhen.ch7.bean")
@Configuration
public class Ch7MainConfigOfLifeCycle {
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加person.......");
        return new Person("person",20);
    }

    //@Scope("prototype")
    @Bean(initMethod="init", destroyMethod="destory")
    public Bike bike(){
        return new Bike();
    }
}

结果

Train......constructor............
Train.......afterPropertiesSet()...
IOC容器创建完成........
Train......destory......

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

  • @PostConstruct: 在Bean创建完成,且属于赋值完成后进行初始化,属于JDK规范的注解
  • @PreDestroy: 在bean将被移除之前进行通知, 在容器销毁之前进行清理工作

Jeep.java

@Component
public class Jeep {
    public Jeep(){
        System.out.println("Jeep.....constructor........");
    }
    @PostConstruct
    public void init(){
        System.out.println("Jeep.....@PostConstruct........");
    }

    @PreDestroy
    public void destory(){
        System.out.println("Jeep.....@PreDestroy......");
    }

}

结果:

Jeep.....constructor........
Jeep.....@PostConstruct........
IOC容器创建完成........
Jeep.....@PreDestroy...

3.后置处理器

负责在初始化方法前后作用。

BeanPostProcessor类[interface]: bean的后置处理器,在bean初始化之前调用进行拦截。
作用:在bean初始化前后进行一些处理工作:

  • 1)postProcessBeforeInitialization():在初始化之前进行后置处理工作(在init-method之前)
    什么时候调用:它任何初始化方法调用之前(比如在InitializingBean的afterPropertiesSet初始化之前,或自定义init-method调用之前使用)
  • 2) postProcessAfterInitialization():在初始化之后进行后置处理工作, 比如在InitializingBean的afterPropertiesSet()
//AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

实现后置处理器接口BeanPostProcessor的JamesBeanPostProcessor.java

@Component
public class JamesBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //返回一个的对象(传过来的对象)
        //在初始化方法调用之前进行后置处理工作,
        //什么时候调用它: init-method=init之前调用
        System.out.println("postProcessBeforeInitialization...."+beanName+"..."+bean);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization...."+beanName+"..."+bean);
        return bean;
    }
}

结果:

Bike constructor..............
postProcessBeforeInitialization....bike...com.wangzhen.ch7.bean.Bike@1e81f160
Bike .....init.....
postProcessAfterInitialization....bike...com.wangzhen.ch7.bean.Bike@1e81f160
IOC容器创建完成........

4.BeanPostProcessor原理以及三个后置处理器的分析(对bean的增强)

BeanPostProcessor的作用:

  • bean的赋值
  • 注入其它组件
  • 生命周期注解功能(都是通过后置处理器来实现注解功能)
  • @Async等等

4.1 后置处理器的跟踪

AnnotationConfigApplicationContext-->refresh()-->
finishBeanFactoryInitialization(beanFactory)--->
beanFactory.preInstantiateSingletons()-->
760行getBean(beanName)--->
199行doGetBean(name, null, null, false)-->
317行createBean(beanName, mbd, args)-->
501行doCreateBean(beanName, mbdToUse, args)-->
541行createBeanInstance(beanName, mbd, args)(完成bean创建)-->
578行populateBean(beanName, mbd, instanceWrapper)(属性赋值)-->
579行initializeBean(beanName, exposedObject, mbd)(Bean初始化)->
1069行到1710行,后置处理器完成对init方法的前后处理.

最终得到如下如下
createBeanInstance(beanName, mbd, args)(完成bean创建)
populateBean(beanName, mbd, instanceWrapper); 给bean进行属性赋值
initializeBean() //初始化Bean方法内容如下,后置处理器对init方法的前后处理
{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd) //执行自定义初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
}

4.2 ApplicationContextAwareProcessor实现分析

此类帮我们组建IOC容器,跟进ApplicationContextAwareProcessor我们发现,这个后置处理器其实就是判断我们的bean有没有实现ApplicationContextAware 接口,并处理相应的逻辑,其实所有的后置处理器原理均如此。
那么怎么组建呢? 只需要实现 ApplicationContextAware 接口。
实现 ApplicationContextAware 接口的Plane.java

@Component
public class Plane implements ApplicationContextAware {
    private ApplicationContext applicationContext;

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

    @PostConstruct
    public void init(){
        System.out.println("Plane.....@PostConstruct........");
    }

    @PreDestroy
    public void destory(){
        System.out.println("Plane.....@PreDestroy......");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //将applicationContext传进来,可以拿到
        this.applicationContext = applicationContext;
    }
}

分析源码如下:

    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
//ApplicationContextAwareProcessor实现的postProcessBeforeInitialization
    @Override
    @Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }
  • step1.在创建Plane对象,还没初始化之前, 先判断是不是实现了ApplicationContextAware接口,
    如果是的话就调用invokeAwareInterfaces方法, 并给里面注入值;

  • step2.进入invokeAwareInterfaces()方法,判断是哪个aware, 如果是ApplicationContextAware, 就将当前的bean转成ApplicationContextAware类型, 调用setApplicationContext(), 把IOC容器注入到Plane里去;

  • step3.用debug调用; 测试用例打断点测试


  • step4.也可看debug调用栈来分析;
    : debug可以打在ApplicationContextAwareProcessor处理器类的applyBeanPostProcessorsBeforeInitialization()方法里, 方便调试, 当bean为Plane类型时,F5跟进看, 最终在 InvokeAwareInterfaces()方法里返回我们的IOC容器applicationContext.

4.3 BeanValidationPostProcessor分析:数据校验


当对象创建完,给bean赋值后,在WEB用得特别多;把页面提交的值进行校验。


4.4 InitDestroyAnnotationBeanPostProcessor


此处理器用来处理@PostConstruct, @PreDestroy, 怎么知道这两注解是前后开始调用的呢, 就是 InitDestroyAnnotationBeanPostProcessor这个处理的。



以@PostConstruct为例, 为什么声明这个注解后就能找到初始化init方法呢?



参考

  • 1)享学课堂James老师笔记
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容