This post is also available in English and alternative languages. Spring Framework版本:5.1.6.RELEASE (点击跳转官方文档)
在 Spring 框架中,BeanPostProcessor 是一个非常重要的接口,它允许开发者在 Spring 容器实例化 Bean 前后,对 Bean 进行一些额外的处理。本文将介绍 BeanPostProcessor 的作用、使用、部分源码分析以及 Spring 内置 BeanPostProcessor。
1. BeanPostPorcessor作用示例 上面提到 BeanPostProcessor 允许开发者在 Spring 容器实例化 Bean 之后,对 Bean 进行一些额外的处理 ,千言万语不如动手写写,通过一个简单示例对其作用有一个初步认识:
在 Bean1 对象中,分别使用 @Autowired、@Resource、@PostConstruct、@PreDestroy 这几个注解进行依赖注入或执行某些动作,便于后续更全面的观察。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static class Bean1 { private Bean2 bean2; private Bean3 bean3; private String javaHome; @Autowired public void setBean2 (Bean2 bean2) { System.out.println("@Autowired 生效:" + bean2); this .bean2 = bean2; } @Resource public void setBean3 (Bean3 bean3) { System.out.println("@Autowired 生效:" + bean3); this .bean3 = bean3; } @Autowired public void setJavaHome (@Value("${JAVA_HOME}") String javaHome) { System.out.println("@Value 生效:" + javaHome); this .javaHome = javaHome; } @PostConstruct public void init () { System.out.println("@PostConstruct 生效" ); } @PreDestroy public void destroy () { System.out.println("@PreDestroy 生效" ); } @Override public String toString () { ... } } public static class Bean2 { }public static class Bean3 { }
1.1. 啥也没有 此示例使用 GenericApplicationContext,这个容器相对来说是「干净」的,它没有像 AnnotationConfigApplicationContext 那样内置一些 BeanPostProcessor,这样便于后续测试观察。
将 Bean1、Bean2、Bean3 手动注入到容器中。在 context.refresh()
方法中,容器会初始化所有单例。最后再手动关闭容器。
1 2 3 4 5 6 7 8 public static void main (String[] args) { GenericApplicationContext context = new GenericApplicationContext (); context.registerBean("bean1" , Bean1.class); context.registerBean("bean2" , Bean2.class); context.registerBean("bean3" , Bean3.class); context.refresh(); context.close(); }
运行后,什么信息也没有输出,说明 @Autowired、@Value、@Resource、@PostConstruct、@PreDestroy 这些注解都没有被解析,因为 GenericApplicationContext 中并没有预先内置 BeanPostProcessor。为此需要手动添加一些 BeanPostPorcessor。
1.2. 添加AutowiredAnnotation处理器 为容器添加 AutowiredAnnotationBeanPostProcessor,这个 Spring 内置 BeanPostProcess 的作用是处理 @Autowired、@Value 注解,并完成依赖注入。
由于在 Bean1 中的 setJavaHome
方法中使用 @Value 注入 String 字符串,因此需要配合使用 ContextAnnotationAutowireCandidateResolver 才能成功,此处先按下不表。
1 2 3 4 5 6 7 8 9 10 public static void main (String[] args) { GenericApplicationContext context = new GenericApplicationContext (); context.registerBean("bean1" , Bean1.class); context.registerBean("bean2" , Bean2.class); context.registerBean("bean3" , Bean3.class); context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver ()); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.refresh(); context.close(); }
运行结果:
1 2 @Autowired 生效:com.yxcheng.example99.a03.TestBeanPostProcessorMainApp02$ Bean2@68267da0 @Value 生效:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home
从结果看 @Autowired、@Value 被处理了,但 @Resource、@PostConstruct、@PreDestroy 这些注解还没有被解析。
1.3. 添加CommonAnnotation处理器 接着为容器添加 CommonAnnotationBeanPostProcessor 处理器,这个 Spring 内置 BeanPostProcess 的作用是处理 @Resource、@PostConstruct、@PreDestroy 注解,并完成依赖注入。
1 2 3 4 5 6 7 8 9 10 11 public static void main (String[] args) { GenericApplicationContext context = new GenericApplicationContext (); context.registerBean("bean1" , Bean1.class); context.registerBean("bean2" , Bean2.class); context.registerBean("bean3" , Bean3.class); context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver ()); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class); context.refresh(); context.close(); }
运行结果:
1 2 3 4 5 @Autowired 生效:com.yxcheng.example99.a03.TestBeanPostProcessorMainApp02$ Bean3@672872e1 @Autowired 生效:com.yxcheng.example99.a03.TestBeanPostProcessorMainApp02$ Bean2@186f8716 @Value 生效:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home @PostConstruct 生效 @PreDestroy 生效
从运行结果看 @Autowired、@Value、@Resource、@PostConstruct、@PreDestroy 这些注解都被解析了。
以上,可以大致了解 Spring 内置的 BeanPostProcessor 的作用,它们为开发者处理了 @Autowired、@Value、@Resource、@PostConstruct、@PreDestroy 这些注解,并进行依赖注入。
2. Spring 内置 BeanPostProcessor 2.1. AutowiredAnnotationBeanPostProcessor 用于处理 @Autowired、@Value 注解,完成依赖注入。
重要方法:
2.2. CommonAnnotationBeanPostProcessor 处理 @Resource、@PostConstruct、@PreDestroy 注解。
3. BeanPostProcessor使用示例 BeanPostProcessor
接口有两个回调方法,postProcessBeforeInitialization
和postProcessAfterInitialization
。
postProcessBeforeInitialization:Bean实例化、属性填充后,初始化(invokeInitMethods
)之前调用。 postProcessAfterInitialization:Bean实例化、属性填充后、初始化(invokeInitMethods
)完成后调用。 这两个方法被执行的源码位置:AbstractAutowireCapableBeanFactory#initializeBean
要使用 BeanPostProcessor,需要创建一个实现了 BeanPostProcessor 接口的类,并将其注册到 Spring 容器中。下面是一个简单的示例:打印所有使用了 @ServiceHandler
注解的类。
1 2 3 4 5 6 7 8 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface ServiceHandler { String key () default "" ; String componentVersion () default "v1" ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Slf4j public abstract class AbstractHandler <T> { protected boolean checkHandler (Object obj) { return Boolean.TRUE; } protected abstract T getByLocalResultCache (Object obj) ; protected abstract T doHandler (Object obj) ; protected abstract void addCache (Object obj, T t) ; public abstract void dynamicUpdateResultCache () ; } @Component @ServiceHandler(key = "asr") public class ASRHandler extends AbstractHandler <Object> { @Override protected Object getByLocalResultCache (Object obj) { return null ; } } @Component @ServiceHandler(key = "tts") public class TTSHandler extends AbstractHandler <Object> { @Override protected Object getByLocalResultCache (Object obj) { return null ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Slf4j @Component public class CustomizeBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { return BeanPostProcessor.super .postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { Class<?> aClass = bean.getClass(); analysisServiceHandlerAnnotation(bean, aClass, aClass.getAnnotation(ServiceHandler.class)); return bean; } private void analysisServiceHandlerAnnotation (Object bean, Class<?> aClass, ServiceHandler serviceHandlerAnn) { if (Objects.isNull(serviceHandlerAnn)) { return ; } String serviceKey = serviceHandlerAnn.key(); String componentVersion = serviceHandlerAnn.componentVersion(); String key = serviceKey + UNDERSCORE + componentVersion; log.info(">>>>> key:[{}],class:[{}]" , key, aClass); } }
运行结果:
1 2 >>>>> key:[asr_ v1],class:[class com.yxcheng.example99.a03.handler.ASRHandler] >>>>> key:[tts_ v1],class:[class com.yxcheng.example99.a03.handler.TTSHandler]
成功获取到了两个使用 @ServiceHandler
注解的实现类。
当然,这种需求还有更优雅的方式,不需要使用自定义注解,利用 Spring 的特性就可以完成提取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Getter @Configuration public class ServiceHandlerConfiguration { public ServiceHandlerConfiguration (Map<String, AbstractHandler> allUseServiceHandlerBean) { this .allUseServiceHandlerBean = allUseServiceHandlerBean; } private final Map<String, AbstractHandler> allUseServiceHandlerBean; } @Slf4j @Component(value = "TTS" + UNDERSCORE + "v1") public class TTSConfigurationV1Handler extends AbstractCommonHandler <Object> { }@Slf4j @Component(value = "ASR" + UNDERSCORE + "v1") public class ASRConfigurationV1Handler extends AbstractCommonHandler <Object> { }
4. Reference