前言
其实是一个老项目,项目中有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
相当于作了映射,或者别名处理。