Spring BeanFactory中bean的生命周期

此文章为本人原创,转载请说明出处。
https://www.jianshu.com/p/0044e351a028
作者:敲破电脑问到底

BeanFactory的继承关系

image.png

我用的Spring 4.3.1.RELEASE版本的

一个bean的一生

通过一个例子了解一下bean生命周期中的一些方法

  1. 首先定义bean类LifeCycleBean
package cn.com.servyou.xqy.burningchart.service.impl;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

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

    private int age;
    private String name;
    private String beanName;
    private BeanFactory beanFactory;

    public BeanLifeCycle() {
        System.out.println("调用构造方法");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        System.out.println("调用自己的setAge设置age属性");
        this.age = age;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("设置BeanFactory,调用BeanFactoryAware.setBeanFactory(BeanFactory beanFactory)");
        this.beanFactory = beanFactory;
    }

    public String getName() {
        return name;
    }

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

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        System.out.println("设置BeanName,调用了BeanNameAware.setBeanName(String s)");
        this.beanName = beanName;
    }

    public void destroy() throws Exception {
        System.out.println("调用摧毁方法,DisposableBean.destroy()");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("我的属性已经设置好,调用了InitializingBean.afterPropertiesSet()");
    }

    @Override
    public String toString() {
        return ",age:" + this.getAge();
    }
}

BeanNameAware, BeanFactoryAware, DisposableBean, InitializingBean都是bean级别的生命周期中的一些方法的接口。

  • setBeanNameBeanNameAware的方法,设置beanName的时候会调用这个方法。
  • setBeanFactoryBeanFactoryAware的方法,设置BeanFactory的时候会调用这个方法。
  • destroy方法是DisposableBean的方法,在bean被摧毁的时候会调用。
  • afterPropertiesSet方法是InitializingBean的方法,在bean的属性被设置好的时候被调用。
  1. 设置BeanFactory容器级的一些方法,这些方法对所有的bean都是有效的,我们这里只选择namebeanLifeCycle的bean进行一些操作
package cn.com.servyou.xqy.burningchart.service.impl;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

import java.beans.PropertyDescriptor;

public class BeanFactoryLifeCycle extends InstantiationAwareBeanPostProcessorAdapter {

    public BeanFactoryLifeCycle() {
    }

    /**
     * 实例化bean之前后处理程序
     *
     * @param aClass
     * @param s
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> aClass, String s) throws BeansException {
        if ("beanLifeCycle".equals(s)) {
            System.out.println("beanLifeCycle还没有被实例化,method:" + "postProcessBeforeInstantiation");
        }

        return null;
    }

    /**
     * 实例化bean之后的后处理程序
     *
     * @param o
     * @param s
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object o, String s) throws BeansException {
        if ("beanLifeCycle".equals(s)) {
            System.out.println("我已经被实例化,method:postProcessAfterInstantiation");
        }

        //这里要返回true,否则不会调用你bean定义中的设置属性值,也不会调用postProcessPropertyValues
        return true;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues propertyValues, PropertyDescriptor[] propertyDescriptors, Object o, String s) throws BeansException {
        if ("beanLifeCycle".equals(s)) {
            System.out.println("我的属性要被设置,method:" + "postProcessPropertyValues");
        }

        return propertyValues;
    }

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        if ("beanLifeCycle".equals(s)) {
            BeanLifeCycle cycle = (BeanLifeCycle) o;
            if (cycle.getAge() == 0) {
                cycle.setAge(999);
                System.out.println("我的age被设置为" + cycle.getAge() + ",method:postProcessBeforeInitialization");
            }

        }

        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        if ("beanLifeCycle".equals(s)) {
            BeanLifeCycle cycle = (BeanLifeCycle) o;
            if (cycle.getAge() != 0) {
                System.out.println("我原来的age" + cycle.getAge());
                cycle.setAge(0);
                System.out.println("age被更改为" + cycle.getAge() + ",method:postProcessAfterInitialization");
            }

        }

        return o;
    }

}
  • 通过继承InstantiationAwareBeanPostProcessorAdapter 类,重写他的四个方法,分别是:
  • postProcessBeforeInstantiation(实例化之前后处理器),
  • postProcessAfterInstantiation(实例化之后后处理器)这里要返回true,否则不会调用你bean定义中的设置属性值,也不会调用postProcessPropertyValues
  • postProcessPropertyValues(设置属性值之前处理器)
  • postProcessBeforeInitialization(初始化之前后处理器)
  • postProcessAfterInitialization(初始化之后后处理器)
    需要注意的是每个方法的返回值,要返回参数列表的bean,不然可能初选NPE问题。
  • 还有就是 postProcessBeforeInitialization(初始化之前后处理器),postProcessAfterInitialization(初始化之后后处理器)最终是来自于BeanPostProcessor接口,这个接口十分重要,BeanPostProcessor接口无需与代码产生耦合,可作为插件注册到Spring容器,充分对bean进行后加工。
  1. bean的xml定义:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanLifeCycle" class="cn.com.servyou.xqy.burningchart.service.impl.BeanLifeCycle"
          destroy-method="destroy">
        <property name="name" value="wang"/>
    </bean>
</beans>
  1. 通过BeanFactory容器调用类,观察它的生命周期
package cn.com.servyou.xqy.burningchart.service;

import cn.com.servyou.xqy.burningchart.service.impl.BeanFactoryLifeCycle;
import cn.com.servyou.xqy.burningchart.service.impl.BeanLifeCycle;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/**
 * @author wangwenj
 */
public class Main {
    public static void main(String[] args) {
        Resource res = new ClassPathResource("spring-config/lifecycle.xml");
        BeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((DefaultListableBeanFactory) factory);
        reader.loadBeanDefinitions(res);
        ((ConfigurableBeanFactory) factory).addBeanPostProcessor(new BeanFactoryLifeCycle());
        BeanLifeCycle cycle = factory.getBean(BeanLifeCycle.class);
        System.out.println(cycle.toString());

        //第二次从缓存中拿出第一次的bean
        BeanLifeCycle cycle2 = factory.getBean(BeanLifeCycle.class);
        System.out.println(cycle2.toString());

        ((DefaultListableBeanFactory) factory).destroySingleton("beanLifeCycle");

    }
}

最后的结果如下所示

beanLifeCycle还没有被实例化,method:postProcessBeforeInstantiation
调用构造方法
我已经被实例化,method:postProcessAfterInstantiation
我的属性要被设置,method:postProcessPropertyValues
设置BeanName,调用了BeanNameAware.setBeanName(String s)
设置BeanFactory,调用BeanFactoryAware.setBeanFactory(BeanFactory beanFactory)
调用自己的setAge设置age属性
我的age被设置为999,method:postProcessBeforeInitialization
我的属性已经设置好,调用了InitializingBean.afterPropertiesSet()
我原来的age999
调用自己的setAge设置age属性
age被更改为0,method:postProcessAfterInitialization
,age:0
,age:0
调用摧毁方法,DisposableBean.destroy()

ApplicationContext与BeanFactory过程也是类似的,只不过多了一个ApplicationContextAware接口,继承此接口Spring会通过setApplicationContext()方法自动注入ApplicationContext上下文。你可以调用get方法获得。

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

推荐阅读更多精彩内容