springboot:BeanPostProcessor示例及分析

Posted PacosonSWJTU

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot:BeanPostProcessor示例及分析相关的知识,希望对你有一定的参考价值。

【README】

1,本文主要分析 BeanPostProcessor 的作用, 开发方式;

2,BeanPostProcessor 是bean后置处理器, 简而言之就是bean被创建好了,之后如果需要对其属性进行修改,则 需要使用  BeanPostProcessor 来起作用;

3,本文还顺带介绍了  InitializingBean 接口; 

  啥都不说,先上代码; 

4, sprinboot的 后置处理器PostProcessor列表小结(这里只讲了4个):

  1. BeanPostProcessor, bean实例化后的 处理器 ; 
  2. InstantiationAwareBeanPostProcessor,实例化装配bean后置处理器,在bean实例化前后干点事情的处理器, 显然执行顺序先于  BeanPostProcessor
  3. SmartInstantiationAwareBeanPostProcessor, 智能实例化装配bean后置处理器,同 InstantiationAwareBeanPostProcessor,不过方法比 InstantiationAwareBeanPostProcessor 多;
  4. DestructionAwareBeanPostProcessor, bean销毁时的处理器;

【1】 BeanPostProcessor 例子

0,借助 BeanPostProcessor ,InitializingBean 在bean创建完成后 进行日志打印;

1,bean接口与类(类实现了 初始化bean接口InitializeingBean )

public interface HelloService {
    public String sayHello();
}

@Service("helloServiceImpl1")
public class HelloServiceImpl1 implements HelloService, InitializingBean {

    public HelloServiceImpl1(){
        System.out.println("HelloServiceImpl1 构造器");
    }
    @Override
    public String sayHello() {
        return "你好我是HelloServiceImpl1";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("HelloServiceImpl1.afterPropertiesSet() 方法");
    }
}

2,后置处理器实现类

/**
 * @Description bean后置处理器
 * @author xiao tang
 * @version 1.0.0
 * @createTime 2021年11月14日
 */
@Component
public class HelloPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 非自定义bean,直接返回
        if (!(bean instanceof HelloService)) {
            return bean;
        } else {
            // 自定义,打印日志
            System.out.printf("bean[%s]初始化前\\n", beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 非自定义bean,直接返回
        if (!(bean instanceof HelloService)) {
            return bean;
        } else {
            // 自定义,打印日志
            System.out.printf("bean[%s]初始化后\\n", beanName);
        }
        return bean;
    }
}

bean后置处理器作用, 在 bean创建完成后,可以通过  postProcessBeforeInitialization 和

postProcessAfterInitialization 修改bean的属性; 

3,测试用例

@SpringBootTest
class Springbt02Config02ApplicationTests {
    @Autowired
    ApplicationContext applicationContext;

    @Test
    void contextLoads() throws SQLException {
        HelloServiceImpl1 impl1 = (HelloServiceImpl1) applicationContext.getBean("helloServiceImpl1");
        System.out.println(impl1.sayHello());
    }
}

打印结果:

HelloServiceImpl1 构造器
bean[helloServiceImpl1]初始化前
HelloServiceImpl1.afterPropertiesSet() 方法
bean[helloServiceImpl1]初始化后
你好我是HelloServiceImpl1

 4,结果解析

很明显, 程序执行顺序为

  1. bean构造器;
  2. BeanPostProcessor-bean后置处理器的 postProcessBeforeInitialization 方法;
  3. InitializingBean的afterPropertiesSet() 方法;
  4. BeanPostProcessor-bean后置处理器的 postProcessAfterInitialization 方法;

【2】BeanPostProcessor 方法调用顺序

【2.1】如何走到  postProcessBeforeInitialization() 方法?

1, 路径如下:

从 SpringApplication.run() 方法走; 

 

 

接着调用 springboot 创建 bean的方法,即 DefaultListableBeanFactory.preInstantiateSingletons() 方法;

 然后调用 AbstractAutowireCapableBeanFactory.doCreateBean() 方法创建给定bean;方法参数:

实际创建指定的bean。 预创建处理此时已经发生,例如 检查 postProcessBeforeInstantiation 回调。
区分默认 bean 实例化、工厂方法的使用和自动装配构造函数。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)   throws BeanCreationException {

创建完成后,调用  AbstractAutowireCapableBeanFactory.initializeBean() 方法初始化给定bean(bean的创建与初始化是 两回事), 方法说明如下:

初始化给定的 bean 实例,应用工厂回调以及 init 方法和 bean 后处理器
从 createBean 调用传统定义的 bean,从 initializeBean 调用现有 bean 实例。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {  

 AbstractAutowireCapableBeanFactory.initializeBean() 方法源码;

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
// 调用bean后置处理器的 postProcessBeforeInitialization() 方法 
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
// 调用  InitializingBean 的 afterPropertiesSet() 方法 
		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()) {
// 调用bean后置处理器的 postProcessAfterInitialization() 方法
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

 这里非常清楚的说明了 bean后置处理器, 初始化bean的方法调用顺序为

  1. bean后置处理器的  postProcessBeforeInitialization ;
  2. 初始化bean接口的  afterPropertiesSet ;
  3. 后置处理器的  postProcessAfterInitialization  ;

【补充】bean后置处理器


 【2.2】 BeanPostProcessor 接口 api

【2.2.1】BeanPostProcessor 类说明

1,允许自定义修改新 bean 实例的工厂钩子 - 例如,检查标记接口或使用代理包装 bean。

通常,通过标记接口等填充 bean 的后处理器将实现 postProcessBeforeInitialization,而使用代理包装 bean 的后处理器通常将实现 postProcessAfterInitialization。

2,登记
ApplicationContext 可以在其 bean 定义中自动检测 BeanPostProcessor bean,并将这些后处理器应用于随后创建的任何 bean。普通的 BeanFactory 允许以编程方式注册后处理器,将它们应用于通过 bean 工厂创建的所有 bean。

3,排序
在 ApplicationContext 中自动检测的 BeanPostProcessor bean 将根据 org.springframework.core.PriorityOrdered 和 org.springframework.core.Ordered 语义进行排序。

相比之下,使用BeanFactory以编程方式注册的 BeanPostProcessor bean 将使用注册顺序;对于以编程方式注册的后处理器(BeanPostProcessor bean ),会忽略掉实现 PriorityOrdered 或 Ordered 接口的排序。此外,@Order 注释不会被 BeanPostProcessor bean 考虑在内。

// bean后置处理器 
public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

【2.2.2】  postProcessBeforeInitialization 方法说明

在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)之前,将此 BeanPostProcessor 应用于给定的新 bean 实例。

bean 已经被填充了属性值。 返回的 bean 实例可能是原始实例的包装器。

默认实现按原样返回给定的 bean。

说白了 ,就是在 InitiaizingBean.afterPropertiesSet() 之前执行;

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

【2.2.3】 postProcessAfterInitialization 方法说明

说白了 ,就是在 InitiaizingBean.afterPropertiesSet() 之后执行;

在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSet 或自定义初始化方法)之后,将此 BeanPostProcessor 应用于给定的新 bean 实例。 bean 已经被填充了属性值。 返回的 bean 实例可能是原始实例的包装器。

在 FactoryBean 的情况下,将为 FactoryBean 实例和 FactoryBean 创建的对象调用此回调(从 Spring 2.0 开始)。 后处理器可以通过相应的 bean instanceof FactoryBean 检查来决定是应用于 FactoryBean 或创建的对象还是两者。

与所有其他 BeanPostProcessor 回调相比,此回调也将在由 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 方法触发的短路后调用。

默认实现按原样返回给定的 bean。

default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

【3】InitializingBean

【3.1】InitializingBean  类说明

由 BeanFactory 设置所有属性后需要响应的 bean 实现的接口:例如 执行自定义初始化,或仅检查是否已设置所有必需属性。

public interface InitializingBean {	
	void afterPropertiesSet() throws Exception;
}

【3.1.1】  afterPropertiesSet 方法说明

在设置所有 bean 属性并满足 BeanFactoryAware、ApplicationContextAware 等要求后,由 包裹的BeanFactory 调用。
此方法允许 bean 实例在设置所有 bean 属性后执行其整体配置和最终初始化的验证。

以上是关于springboot:BeanPostProcessor示例及分析的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot入门到精通-SpringBoot启动流程

SpringBoot入门到精通-SpringBoot自定义starter

SpringBoot.06.SpringBoot日志管理

SpringBoot.06.SpringBoot日志管理

最全面的SpringBoot教程——SpringBoot概述

SpringBoot入门到精通-SpringBoot集成SSM开发项目