BeanPostProcessor
2025-01-22 08:19:30    1.4k 字   
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 注解,完成依赖注入。

重要方法:

  • AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata

    在 Bean 中查找,哪些属性(成员变量)、方法参数上添加了 @Autowired 注解。然后通过反射进行依赖注入。


2.2. CommonAnnotationBeanPostProcessor

处理 @Resource、@PostConstruct、@PreDestroy 注解。


3. BeanPostProcessor使用示例

BeanPostProcessor接口有两个回调方法,postProcessBeforeInitializationpostProcessAfterInitialization

  • 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


  1. 1.Bean后置处理器