重识Spring的BeanPostProcessor处理器
BeanPostProcessor
是Spring用来实现快速拓展最为核心的接口,现在常说的AOP就是通过实现BeanPostProcessor接口来进行拓展。
下面就先看下BeanPostProcessor到底长什么样?🧐
BeanPostProcessor接口
public interface BeanPostProcessor {
//在bean init之前执行
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 在bean执行完init方法之后执行
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor中就两个方法,postProcessBeforeInitialization和postProcessAfterInitialization,分别会在Spring执行invokeInitMethods方法(包含了afterPropertiesSet和自定义init方法)前后进行执行。
这里要特别注意BeanPostProcessor中方法的最后一个单词是Initialization,这个很容易和postProcessBeforeInstantiation/postProcessAfterInstantiation方法混淆,两者的调用时机是不一样的,Initialization是在初始化前后,而Instantiation是在实例化前后。
下面介绍下BeanPostProcessor用途比较重要的两个实现:CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor。
Spring会在添加<context:component-scan > XML配置以及@ComponentScan()注解时创建默认的CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor处理器。
CommonAnnotationBeanPostProcessor
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPBRGckJTWxhnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5ITN2UjNzMTMwIDNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
最上层实现就是
BeanPostProcessor
接口。
CommonAnnotationBeanPostProcessor
支持常见的Java注解,特别是JSR-250注解,所以大部分的注解都会关于“资源”的构建、销毁和使用。
因为实现了InitDestroyAnnotationBeanPostProcessor接口,所以支持
@PostConstruct
,
@PreDestroy
关于对象初始化和销毁的注解。
支持注解如下:
- @Resource
- @PostConstruct
- @PreDestroy
- @WebServiceRef
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 在bean实例化之前调用
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 在bean实例化之后调用
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
/**
* 当使用注解的时候,通过这个方法来完成属性的注入
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
/**
* 属性注入后执行的方法,在5.1版本被废弃
*/
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
如何解析
CommonAnnotationBeanPostProcessor
类中有如下方法会在Bean初始化后执行,用来填充BeanDefinition中的初始化方法以及@Resource对应的字段定义;
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 处理@PostConstruct和@PreDestroy注解
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 处理@Resouce注解对应的属性以及方法
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
postProcessMergedBeanDefinition
实际调用的是父类
InitDestroyAnnotationBeanPostProcessor
中的方法;
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 获取生命周期方法
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
// 验证相关方法
metadata.checkConfigMembers(beanDefinition);
}
findLifecycleMetadata方法中会调用**buildLifecycleMetadata()**方法来构建对应生命周期方法的LifecycleElement(这里主要是@PostConstruct或者@PreDestroy注解对应的方法)。
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
// @PostConstruct方法
List<LifecycleElement> initMethods = new ArrayList<>();
// @PreDestroy方法
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
// 遍历当前类以及父类所有方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 当前方法的注解中包含initAnnotationType注解时(@PostConstruct)
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
// 如果有,把它封装成LifecycleElement对象,存储起来
LifecycleElement element = new LifecycleElement(method);
// 将创建好的元素添加到集合中
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
// 当前方法的注解中包含destroyAnnotationType注解(PreDestroy)
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
// 如果有,把它封装成LifecycleElement对象,存储起来
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
// 获取父类class对象
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
buildLifecycleMetadata
方法会封装类中对应生命周期方法的元数据,通过
getDeclaredMethods()
获取类中的所有方法,然后判断是否使用了**@PostConstruct或者@PreDestroy**注解,是就会以
LifecycleMetadata
的形式放入到
lifecycleMetadataCache
中,并且一层一层获取父类相关内容。
而
findResourceMetadata
方法同样会调用
buildResourceMetadata
方法来构建@Resource注解对应的属性或方法的ResourceElement。
也就是存在如下数据存放方式:
InjectionMetadata -> Collection injectedElements -> ResourceElement
LifecycleMetadata -> Collection initMethods / destroyMethods -> LifecycleElement
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
// 判断当前的类是否是Resource或javax.xml.ws.WebServiceRef类
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// @Resource属性注入
// 查询是否有webService,ejb,Resource的属性注解,但是不支持静态属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
//注意静态字段不支持
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
//如果不想注入某一类型对象 可以将其加入ignoredResourceTypes中
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
//字段会封装到ResourceElement
currElements.add(new ResourceElement(field, field, null));
}
}
});
// @Resource方法注入
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//如果重写了父类的方法,则使用子类的
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
// 静态字段不支持
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
// 不支持静态方法
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
// 父类的都放在第一位,所以父类是最先完成依赖注入的
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
buildResourceMetadata
方法和
buildLifecycleMetadata
实现基本一样,只不过是加了字段的遍历以及最后生成的元数据不一样罢了。
PS:
这里获取类字段和方法的函数,Spring也是进行了充分的优化;
private static Field[] getDeclaredFields(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
Field[] result = declaredFieldsCache.get(clazz);
if (result == null) {
try {
// 获取clazz所有定义的属性
result = clazz.getDeclaredFields();
// EMPTY_FIELD_ARRAY和result在没有字段情况下都是空数组,所以用一个固定的空数组来表示,减少新对象的内存占用
declaredFieldsCache.put(clazz, (result.length == 0 ? EMPTY_FIELD_ARRAY : result));
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() +
"] from ClassLoader [" + clazz.getClassLoader() + "]", ex);
}
}
// 返回clazz的属性数组
return result;
}
首先,Spring将所有对应的方法或字段都放入到了Map缓存中。
此外,下面这行代码;
declaredFieldsCache.put(clazz, (result.length == 0 ? EMPTY_FIELD_ARRAY : result));
在缓存中还没有对应类的字段或方法时,通过Class类的
getDeclaredFields
方法先获取到,然后放入map集合中,主要是这里会对获取的数组长度做个判断,当为0时,实际放入的是EMPTY_FIELD_ARRAY对象,而EMPTY_FIELD_ARRAY定义如下;
EMPTY_FIELD_ARRAY实际就是一个长度为0的数组,实际上EMPTY_FIELD_ARRAY和类字段或方法不存在时代表的含义是相同的,而getDeclaredFields和getDeclaredMethods方法每次都会返回一个新数组,所以Spring利用EMPTY_FIELD_ARRAY作了代替,来让result数组较早的回收,就是为了减少内存的消耗。
AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor从类名的定义上就能看出,该处理器主要适合**@Autowired**注解相关的。该处理器和CommonAnnotationBeanPostProcessor处理器执行的时间都是一样的,只是会后于CommonAnnotationBeanPostProcessor处理器执行。
这里只介绍相关的几个重要方法。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 遍历类中的每个属性,判断属性是否包含指定的属性(通过 findAutowiredAnnotation 方法)
// 如果存在则保存,这里注意,属性保存的类型是 AutowiredFieldElement
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
//Autowired注解不支持静态方法
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
//查看是否是required的
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 遍历类中的每个方法,判断属性是否包含指定的属性(通过 findAutowiredAnnotation 方法)
// 如果存在则保存,这里注意,方法保存的类型是 AutowiredMethodElement
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
// 如果方法没有入参,输出日志,不做任何处理
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// AutowiredMethodElement里封装了一个PropertyDescriptor(比字段多了一个参数)
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 父类的都放在第一位,所以父类是最先完成依赖注入的
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// InjectionMetadata就是对clazz和elements的一个包装而已
return InjectionMetadata.forElements(elements, clazz);
}
@Autowired处理器和@Resource处理器相比,方法类似,都是获取到所有的字段或者方法,然后遍历进行相应的判断处理。@Autowired处理器相对而言,包装的类型发生了变化(AutowiredMethodElement,AutowiredMethodElement),并且,在@Autowired下,所有对象的注入都是从父类开始的,也就是说在同注解的属性注入时,父类的属性注入会先于子类的属性注入。
两个处理器在populateBean对象注入的时候,执行的逻辑都是如下所示:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 这里获取到的是之前解析保存的Metadata
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
findResourceMetadata
从之前解析类时所保存在BeanPostProcessor中的
injectionMetadataCache
Map集合中获取到InjectionMetadata对象,然后执行inject方法,循环遍历注入。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
拓展:BeanPostProcessor执行顺序
- 实现了PriorityOrdered接口 > Ordered接口 > 两者都没实现;
- 实现了MergedBeanDefinitionPostProcessor一定最后执行;
- 相同情况下,还是按照PriorityOrdered > Ordered相对顺序。
相同情况下比较如下:
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
// 判断o1是否实现了PriorityOrdered接口
boolean p1 = (o1 instanceof PriorityOrdered);
// 判断o2是否实现了PriorityOrdered接口
boolean p2 = (o2 instanceof PriorityOrdered);
// 如果o1实现了PriorityOrdered接口,o2没有,则o1排前面
if (p1 && !p2) {
return -1;
}
// 如果o2实现了PriorityOrdered接口,而o1没有,o2排前面
else if (p2 && !p1) {
return 1;
}
// 如果o1和o2都实现或者都没有实现PriorityOrdered接口
// 拿到o1的order值,如果没有实现Ordered接口,值为Ordered.LOWEST_PRECEDENCE
int i1 = getOrder(o1, sourceProvider);
// 拿到o2的order值,如果没有实现Ordered接口,值为Ordered.LOWEST_PRECEDENCE
int i2 = getOrder(o2, sourceProvider);
// 通过order值排序(order值越小,优先级越高)
return Integer.compare(i1, i2);
}