Spring boot BeanPostProcessor优先级

前言

其实是一个老项目,项目中有aop,有BeanPostProcessor注入Spring bean的属性。当orader一样时,那么加载顺序就很重要。如何保证绝对的加载逻辑就与Spring的原理相关了。源码简单分析即可明白Spring的设计。

 

1. demo构造

1.1 demo

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-boot-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.3.5.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>

    </dependencies>
</project>

构建aop一个,controller一个,BeanPostProcessor逻辑一个

package com.feng.boot.aop;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

//@Aspect
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {

    @Bean
    public DemoAspect getAspectDemo(){
        return new DemoAspect();
    }
}

package com.feng.boot.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class DemoAspect {

    @Around("execution(* com.feng.boot.bean.DemoController.*(..))")
    public Object around(ProceedingJoinPoint pjp) {
        try {
            Object o =  pjp.proceed();
            return o;
        } catch (Throwable e) {
            return null;
        }
    }
}

package com.feng.boot.bean;

import com.feng.boot.anno.InjectFieldAnno;
import com.feng.boot.anno.InjectFieldBean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @InjectFieldAnno(name = "feng")
    private InjectFieldBean injectFieldBean;

    @RequestMapping("/hello")
    public String testDemo(String param){
        return injectFieldBean.invokeMethod(param);
    }
}

package com.feng.boot.processor;

import com.feng.boot.anno.InjectFieldAnno;
import com.feng.boot.anno.InjectFieldBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Component
public class FieldInjectBean implements BeanPostProcessor, Ordered {
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Field[] fields = bean.getClass().getDeclaredFields();
        InjectFieldAnno injectFieldAnno;
        for (Field field : fields) {
            injectFieldAnno = field.getAnnotation(InjectFieldAnno.class);
            if (injectFieldAnno != null) {
                InjectFieldBean injectFieldBean = new InjectFieldBean();
                injectFieldBean.setName(injectFieldAnno.name());
                field.setAccessible(true);
                try {
                    field.set(bean, injectFieldBean);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        return bean;
    }

    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE-1;
    }
}

辅助类

package com.feng.boot.anno;

public class InjectFieldBean {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String invokeMethod(String param){
        return this.name;
    }
}

package com.feng.boot.anno;

import java.lang.annotation.*;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InjectFieldAnno {
    String name() default "";
}

1.2 运行demo hello

经过AOP

然后发现,自定义属性并没有注入

2. 原因分析

2.1 源码分析原因

Spring创建bean的源码

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

其中有个核心方法,在初始化bean的对象时,会处理

BeanPostProcessors

源码如下:applyBeanPostProcessorsAfterInitialization

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

继续跟踪,可以看见是先执行Spring的beanpostprocessors,毕竟for循环。

因为创建返回代理类

跟踪我们会发现这里因为引入了AOP,有一个AOP的处理逻辑,可以看到我们实际上把属性注入了Spring的代理类

2.2 根因分析

上面分析了直接原因,实际原因与getBeanPostProcessors()有决定性的因素,那么这个processors在哪里注入的呢

org.springframework.context.support.PostProcessorRegistrationDelegate

源码如下:

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
        //拿到所有BeanPostProcessor的bean名称
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
        //区分内部与优先级更高的processors priorityOrderedPostProcessors 然后是ordered排序,这个是这个问题的关键
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
        //先排序一次priorityOrderedPostProcessors 注册
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
        //上面说的非常明显
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}

        //排序orderedPostProcessors
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
        //nonOrderedPostProcessors 非ordered的nonOrderedPostProcessors
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
        // 非ordered的nonOrderedPostProcessors registry
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

        //注册internalPostProcessors
		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

至此,根因已经很清楚了,那么就很容易解决

3. 解决办法

笔者由于需要在AOP前注入属性,那么必须优先级高于AOP的processors,由于AOP的ordered是最大值

那么将自定义的processors设置为

priorityOrdered

即可解决问题,而且保证一定优先于AOP。

总结

其实这个问题很简单,Spring在设计时,制定了比较优秀的规则,比如状态机制,优先级。查看Spring官网或者源码即可分析解决问题。其实还有一个实现接口

BeanFactoryPostProcessor
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

区别是这个是bean定义的时候处理定义内容,而BeanPostProcessor是bean创建的时候

 

这里有个有意思的问题,Spring找的beanName

而实际创建的对象,是不是不一致,😄

实际上是Spring刻意为之:

org.springframework.context.annotation.AspectJAutoProxyRegistrar

注册的时候指定了类

但是指定名称却是另一个,并且指定了order为 Ordered.HIGHEST_PRECEDENCE

相当于作了映射,或者别名处理。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值