Spring boot BeanPostProcessor优先级

前言

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

 

1. demo构造

1.1 demo

pom



    4.0.0

    org.example
    spring-boot-demo
    1.0-SNAPSHOT

    
        
            org.springframework.boot
            spring-boot-starter-web
            2.3.5.RELEASE
        
        
            org.springframework.boot
            spring-boot-starter-test
            2.3.5.RELEASE
            test
        
        
            org.springframework.boot
            spring-boot-starter-aop
            2.3.5.RELEASE
        

    

构建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

Spring boot BeanPostProcessor优先级_第1张图片

经过AOP

Spring boot BeanPostProcessor优先级_第2张图片

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

Spring boot BeanPostProcessor优先级_第3张图片

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) () -> {
				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循环。

Spring boot BeanPostProcessor优先级_第4张图片

因为创建返回代理类

Spring boot BeanPostProcessor优先级_第5张图片

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

Spring boot BeanPostProcessor优先级_第6张图片

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 priorityOrderedPostProcessors = new ArrayList<>();
		List internalPostProcessors = new ArrayList<>();
		List orderedPostProcessorNames = new ArrayList<>();
		List 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 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 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是最大值

Spring boot BeanPostProcessor优先级_第7张图片

那么将自定义的processors设置为

priorityOrdered

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

总结

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

BeanFactoryPostProcessor
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

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

 

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

Spring boot BeanPostProcessor优先级_第8张图片

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

Spring boot BeanPostProcessor优先级_第9张图片

实际上是Spring刻意为之:

org.springframework.context.annotation.AspectJAutoProxyRegistrar

Spring boot BeanPostProcessor优先级_第10张图片

注册的时候指定了类

Spring boot BeanPostProcessor优先级_第11张图片

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

Spring boot BeanPostProcessor优先级_第12张图片

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

你可能感兴趣的:(spring,boot,spring,boot,aop)