Spring扩展接口BeanPostProcessor详解

本文详细介绍了Spring Boot中BeanPostProcessor的概念、执行时机及其在启动过程中的作用。通过示例展示了如何利用BeanPostProcessor在Bean初始化前后进行操作,实现自定义Bean的包装和处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,
  先理一下这个方法的逻辑:

  1. 首先,筛选出bean工程中存在的所有实现BeanPostProcessor类的类名称,再注册一个BeanPostProcessorChecker的bean,这个bean只是用来对在bean不适合所有的BeanPostProcessor调用的情况下打印一些日志信息。
  2. 对BeanPostProcessor进行整理,如果不进行整理,spring是无法精确按既定的顺序执行所有BeanPostProcessor。注册顺序为:
    ①注册实现了PriorityOrdered接口的BeanPostProcessor。
    ②注册实现了Ordered接口的的BeanPostProcessor。
    ③注册无任何实现的BeanPostProcessor。
    ④注册实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
  3. 注册一个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值