其实是一个老项目,项目中有aop,有BeanPostProcessor注入Spring bean的属性。当orader一样时,那么加载顺序就很重要。如何保证绝对的加载逻辑就与Spring的原理相关了。源码简单分析即可明白Spring的设计。
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 "";
}
经过AOP
然后发现,自定义属性并没有注入
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
继续跟踪,可以看见是先执行Spring的beanpostprocessors,毕竟for循环。
因为创建返回代理类
跟踪我们会发现这里因为引入了AOP,有一个AOP的处理逻辑,可以看到我们实际上把属性注入了Spring的代理类
上面分析了直接原因,实际原因与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));
}
至此,根因已经很清楚了,那么就很容易解决
笔者由于需要在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
相当于作了映射,或者别名处理。