专栏首页技术进阶之路Spring 中控制 Bean 生命周期的几种方式及 BeanPostProcessor 执行原理

Spring 中控制 Bean 生命周期的几种方式及 BeanPostProcessor 执行原理

一、几种方式总览

  1. @Bean 注解的方式;
  2. 通过实现接口的方式;
  3. 使用 JSR250 提供的两个注解;
  4. BeanPostProcessor 后置处理器;

二、@Bean 的方式

可以使用 @Bean 注解的两个属性设置初始化和销毁方法:

@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
    return new Car();
}

这里在实体类中创建了几个方法。

public class Car {

    public Car() {
        System.out.println("汽车构造器...");
    }

    public void init() {
        System.out.println("汽车初始化...");
    }

    public void destroy() {
        System.out.println("汽车销毁了...");
    }
}

实际的测试结果如下:

汽车构造器...
汽车初始化了...
容器初始化了...

三、InitializingBean 和 DisposableBean 的方式

这两个类都是接口,其中 InitializingBean 有一个抽象方法 afterPropertiesSetDisposableBean 有一个抽象方法 destroy,分别代表 initdestroy 方法。

继承之后可以重写这两个方法:

public void destroy() {
    System.out.println("汽车销毁了...");
}
@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("汽车初始化了...");
}

效果也和上面一样,这样就不用再使用 @Bean 指定初始化和销毁方法了。

注意:

  • 这里的对象均为单例的对象,所以在容器初始化的时候就加载了;
  • 注意如果是多例的对象要加以区分。

四、@PostConstruct 和 @PreDestroy 注解

这两个注解都是 JSR250 提供的注解:

  • @PostConstruct: 在 bean 创建完成并且属性赋完值的时候调用方法;
  • @PreDestroy: 在容器销毁 bean 之前通知我们进行清理操作;

该注解在实体类上的方法使用:

/**
 * 对象创建并赋值之后调用
 */
@PostConstruct
public void init() {
    System.out.println("汽车初始化...");
}
/**
 * 容器移除对象之前调用
 */
@PreDestroy
public void destroy() {
    System.out.println("汽车销毁了...");
}

五、BeanPostProcessor 后置处理器

该类的作用就是在 bean 初始化前后进行一些处理工作,它是一个接口;

该接口有两个方法:

  • postProcessBeforeInitialization:在初始化之前调用;
  • postProcessAfterInitialization: 在初始化之后调用;

所以我们可以写一个实现类来实现这些方法:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前:" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后:" + beanName);
        return bean;
    }
}

执行之后,这两个方法会在初始化方法被调用的前后分别被调用,应用于容器中所有的 bean

六、BeanPostProcessor 的执行原理

下面分析一下 BeanPostProcessor 的执行原理:

这是截取的一段源代码,出自 AbstractAutowireCapableBeanFactory 类,该方法叫做 doCreateBean

// Initialize the bean instance.
Object exposedObject = bean;
try {
	populateBean(beanName, mbd, instanceWrapper);
	exposedObject = initializeBean(beanName, exposedObject, mbd);
}

这段代码很容易理解,就是初始化 bean 实例,涉及两个方法:

  • populateBean:将属性值填充到 Bean 中,就是给 Bean 属性赋值;
  • initializeBean:初始化 Bean

来看一下该类的 initializeBean 方法做了什么:

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);
}

该方法中有三处比较重要:

  • applyBeanPostProcessorsBeforeInitialization:在 Bean 初始化之前执行;
  • invokeInitMethods:执行自定义初始化;
  • applyBeanPostProcessorsAfterInitialization:在 Bean 初始化之后执行;

查看前置方法的源码,发现他就是循环遍历所有的 BeanPostProcessor ,然后依次执行,后置方法同理。

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

而且这两个方法和我们写实现类重写的两个方法同名,作用也一致,这里是 Spring 使用了代理模式进行了增强,我们重写的部分就是增强的内容。

注:

Spring 底层很多地方都使用了 BeanPostProcessor 及其子类,如 AutowiredAnnotationBeanPostProcessor,就是 @Autowired 注解。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 深入分析 Spring 基于注解的 AOP 实现原理

    整个 AOP 要想起作用,必须加上 @EnableAspectJAutoProxy 注解,这个注解的作用是什么呢?

    wsuo
  • 数据库原理01——概述

    本系列文章为笔者在校学习《数据库原理及应用》课程所作的课程笔记,文中大部分内容参考王珊的《数据库系统概论》

    wsuo
  • Java 自定义 ArrayList 与 LinkedList

    wsuo
  • 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?

    在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean...

    程序员DMZ
  • 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?

    在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean...

    程序员DMZ
  • Spring Ioc 之 Bean的加载(三):各个 scope 的 Bean 创建

    createBean(beanName, mbd, args)方法比较复杂,在之后的文章中会详细分析,这里就先略过,直接看

    大王叫下
  • Spring IoC 源码分析 (基于注解) (三)之 Bean的解析与注册

    在上一篇文章Spring IoC 源码分析 (基于注解) 之 包扫描中,我们介绍了Spring基于注解扫描包获取bean的过程。本文我们将一起探讨spring对...

    大王叫下
  • Spring5 源码学习 (9) doGetBean 概述

    接上回,AbstractApplicationContext#refresh调用AbstractApplicationContext#finishBeanFac...

    Coder小黑
  • Spring源码学习笔记(9)——AOP

    AOP的定义及一些术语相信大家已经很熟悉了,这里不再赘述。下面演示基于注解的Spring AOP开发。

    张申傲
  • Spring源码学习笔记(2)——Bean的加载

    张申傲

扫码关注云+社区

领取腾讯云代金券