Spring扩展接口BeanPostProcessor详解
1.BeanPostProcessor概念
BeanPostProcessor翻译过来即为Bean的后置处理器,是Spring提供的众多基于Bean生命周期定义的扩展接口中的一个,一般用于Spring IOC容器初始化时对容器中的Bean进行包装。BeanPostProcessor接口包含两个抽象方法:
//以下代码摘自org.springframework.beans.factory.config.BeanPostProcessor
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
其中postProcessBeforeInitialization方法会在每个Bean对象的显式初始化方法执行之前执行,postProcessAfterInitialization方法会在每个Bean对象的显式初始化方法执行之后执行。
Bean对象的显式初始化方法一般包括实现了InitializingBean接口后重写的afterPropertiesSet方法以及自定义的init-method指定的方法,此处的‘显式’一般指要给bean的某些属性手动赋值或手动执行某方法,具体参阅##https://www.jianshu.com/p/0c8a1b5e3808
2.BeanPostProcessor在SpringBoot启动过程中的执行时机
SpringBoot在启动的时候会调用run()方法,在经过一系列调用之后,会执行refresh()方法,在此方法中会完成应用上下文的初始化工作,在本篇文章中我们只关注BeanPostProcessor的注册过程和执行时机。
//以下代码摘自org.springframework.context.support.AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
...
//注册bean处理器,以在bean创建过程中完成对bean的自定义包装
registerBeanPostProcessors(beanFactory);
...
//对bean进行实例化,执行BeanPostProcessor类中的方法
finishBeanFactoryInitialization(beanFactory);
}
从上面代码中可以看到,BeanPostProcessor会在外部bean创建之前先注册到ApplicationContext中,保证BeanPostProcessor能够参与到bean的创建过程中。
我们再看registerBeanPostProcessors方法。
//以下代码摘自org.springframework.context.support.AbstractApplicationContext
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
方法中调用了PostProcessorRegistrationDelegate类的静态方法registerBeanPostProcessors,
先理一下这个方法的逻辑:
- 首先,筛选出bean工程中存在的所有实现BeanPostProcessor类的类名称,再注册一个BeanPostProcessorChecker的bean,这个bean只是用来对在bean不适合所有的BeanPostProcessor调用的情况下打印一些日志信息。
- 对BeanPostProcessor进行整理,如果不进行整理,spring是无法精确按既定的顺序执行所有BeanPostProcessor。注册顺序为:
①注册实现了PriorityOrdered接口的BeanPostProcessor。
②注册实现了Ordered接口的的BeanPostProcessor。
③注册无任何实现的BeanPostProcessor。
④注册实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
。 - 注册一个ApplicationListenerDetector的bean,用于判断bean是否是ApplicationListener类型。
下面看代码:
//以下代码摘自org.springframework.context.support.PostProcessorRegistrationDelegate
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 筛选出bean工程中存在的所有实现BeanPostProcessor类的类名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 注册一个BeanPostProcessorChecker的bean
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 对BeanPostProcessor的不同实现进行分类
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 为PriorityOrdered类型
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
//为ordered类型
orderedPostProcessorNames.add(ppName);
}
else {
//无序类型
nonOrderedPostProcessorNames.add(ppName);
}
}
// 排序并注册PriorityOrdered类型的BeanPostProcessor实现类
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//根据BeanPostProcessor实现类名称获取其实例
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//排序并注册ordered类型的BeanPostProcessor实现类
sortPostProcessors(beanFactory, orderedPostProcessors);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 获取实例
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//注册无序类型的BeanPostProcessor实现类
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最后排序并注册内部的BeanPostProcessor实现类
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
继续跟进registerBeanPostProcessors的重载方法。
//以下代码摘自org.springframework.context.support.PostProcessorRegistrationDelegate
/**
* 注册给定的BeanPostProcessor.
*/
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
在重载方法中,又调用了ConfigurableListableBeanFactory 实现类的addBeanPostProcessor方法,方法如下
//以下代码摘自org.springframework.context.support.AbstractApplicationContext
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
//this.beanPostProcessors为AbstractApplicationContext抽象类的属性,用于存放所有的BeanPostProcessor实现类
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}
以上,即为BeanPostProcessor的注册过程。
然后分析refresh()方法中的finishBeanFactoryInitialization函数,主要是对bean进行初始化。下面对finishBeanFactoryInitialization方法持续进行跟进后,找到的BeanPostProcessor的执行是在initializeBean方法中。
//以下代码摘自org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
@Override
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
...
if (mbd == null || !mbd.isSynthetic()) {
//执行Bean初始化方法之前执行所有BeanPostProcessor实现类中的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//bean执行初始化方法。跟进此方法可以验证前面所说的一般bean执行初始化方法的两种方式
invokeInitMethods(beanName, wrappedBean, mbd);
}
...
if (mbd == null || !mbd.isSynthetic()) {
//执行Bean初始化方法之后执行所有BeanPostProcessor实现类中的postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
//以下代码摘自org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
在上面代码中可以看到,在bean初始化方法执行之前会先执行所有BeanPostProcessor实现类中的postProcessBeforeInitialization方法,当for循环到我们的processor时,就会执行我们的处理逻辑,就实现了对bean的再包装,同样的,applyBeanPostProcessorsAfterInitialization与before类似,只不过是在初始化方法之后执行。
3.DEMO
有这样一个需求,获取配置文件application.yml中的加密属性,然后在解密后注入到bean的属性中去。
首先写启动类,实体类,配置文件,如下。
//启动类
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ac = SpringApplication.run(DemoApplication.class, args);
People people = (People) ac.getBean("people");
people.say();
}
@Bean
public BeanPostProcessor AnnotationBeanPostProcessor(ConfigurableEnvironment environment){
return new AnnotationBeanPostProcessor(environment);
}
}
//实体类
@Component
public class People{
//value支持 "${some.key}" "${some.key:defaultValue}" "defaultValue"
@DecryptValue(value = "${test.demo}")
private String name;
//省略getter seteer
...
public void say(){
System.out.println("我是"+name);
}
}
//配置文件 application.yml
test:
demo: zhangsan
自定义注解,用来标志bean的哪些属性在注入前是需要被解密的。在上面People实体类中,属性name被注解@DecryptValue标志。
//自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
public @interface DecryptValue {
//占位符或者默认值
String value();
}
我们将处理逻辑放在后置处理器中,因此,具体实现处理逻辑的AnnotationBeanPostProcessor类需要实现BeanPostProcessor接口。在这里,我首先定义了一个AbstractAnnotationBeanPostProcessor抽象类,以方便于后面程序的扩展。
public abstract class AbstractAnnotationBeanPostProcessor implements BeanPostProcessor,PriorityOrdered {
//这个方法是在bean初始化之前执行的,编写处理过程,实际的处理逻辑在抽象方法processField中,需要子类去实现
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Class<?> clazz = bean.getClass();
for (Field field : findAllFields(clazz)) {
processField(bean,beanName,field);
}
return bean;
}
//通过反射获取bean的所有field
private List<Field> findAllFields(Class clazz) {
List<Field> fields = new ArrayList<>();
ReflectionUtils.doWithFields(clazz, (field) -> {fields.add(field);});
return fields;
}
protected abstract void processField(Object bean, String beanName, Field field);
//这个方法是在bean初始化之后执行的,不做任何处理,直接返回bean
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
在AbstractAnnotationBeanPostProcessor 这个抽象类中,重写了postProcessBeforeInitialization方法,在此方法中,反射获取bean的所有field,对这些field进行处理,循环调用实际处理方法processField(这个方法需要由子类实现)。下面是实现类。
public class AnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor {
private ConfigurableEnvironment environment;
public AnnotationBeanPostProcessor(ConfigurableEnvironment environment){
this.environment = environment;
}
@Override
protected void processField(Object bean, String beanName, Field field) {
DecryptValue neptuneAnnotation = AnnotationUtils.getAnnotation(field, DecryptValue.class);
if (neptuneAnnotation == null){
return;
}
String propertyString = neptuneAnnotation.value();
String decryptedValue = null;
//对注解的value值进行解析
Map<String, String> keyAndDefaultValue = PlaceHolderResolver.obtainPlaceHolderKey(propertyString);
for (Map.Entry<String, String> entry : keyAndDefaultValue.entrySet()) {
String valueBeforeDecrypt = environment.getProperty(entry.getKey());
if (valueBeforeDecrypt != null){
//todo 对valueBeforeDecrypt的解密过程,在此直接赋值,省略解密过程,经过解密后,会将zhangsan 解析成 lisi
decryptedValue = "lisi";
}else {
String defaultValue = entry.getValue();
if (defaultValue == null){
throw new RuntimeException(
String.format("Could not resolve placeholder '%s' in neptuneDecryptValue \"%s\""
,entry.getKey()
,propertyString));
}else {
decryptedValue = defaultValue;
}
}
}
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field,bean,decryptedValue);
}
}
在AnnotationBeanPostProcessor 实现类中,我们主要做了两件事,一件是对field上@DecryptValue注解的值进行解析(具体解析过程在PlaceHolderResolver类中),另一件是利用反射为bean的属性注入解析后的值。下面是自定义注解的值的解析类。
public class PlaceHolderResolver {
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private static final String VALUE_SEPARATE = ":";
/**
* 提取占位符中的key
* 支持的格式:
* ${key} 提取出key
* ${key:defaultValue} 提取出key和defaultValue
* 如果不是占位符,直接提取
* @param propertyString
* @return
*/
public static Map<String, String> obtainPlaceHolderKey(String propertyString) {
Map<String, String> keyAndDefaultValue = Maps.newHashMap();
if (propertyString.startsWith(PLACEHOLDER_PREFIX)
&& propertyString.endsWith(PLACEHOLDER_SUFFIX)) {
String placeholder = propertyString.substring(PLACEHOLDER_PREFIX.length(), propertyString.length()-1);
if (placeholder.indexOf(VALUE_SEPARATE) != -1) {
String[] split = placeholder.split(VALUE_SEPARATE);
if (StringUtils.isBlank(split[0])){
throw new RuntimeException("Resolve placeholder error! placeholder: "+propertyString);
}
keyAndDefaultValue.put(split[0],split[1]);
}else {
keyAndDefaultValue.put(placeholder,null);
}
}else {
keyAndDefaultValue.put(propertyString,null);
}
return keyAndDefaultValue;
}
}
启动demo工程,控制台打印"我是lisi"。
此demo工程已放在github上,地址: https://github.com/992762947/BeanPostProcessorDemo.git