主要内容
SpringBoot如何将AOP相关的类注入BeanFactory中,如何起作用呢?
梳理概要
- AopAutoConfiguration:自动注入AOP相关的配置类;AnnotationAwareAspectJAutoProxyCreator;
- 在populateBean的时候,每个bean都会扫描是否有切面,匹配一下;AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization;
- 匹配成功,则会经过cglib动态代理生成一个新的代理类;
- 加载AopAutoConfiguration
- 在加载CglibAutoProxyFactory的时候,里面有注解@EnableAspectJAutoProxy的时候有一个@Import注解,AspectJAutoProxyRegistrar;这个Registrar很重要!!!
文章图片
其在ConfigurationClassPostProcessor类扫描加载bean的时候,处理loadBeanDefinitionsFromRegistrars的时候;加载进去;
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); .....
registerAspectJAnnotationAutoProxyCreatorIfNecessary()的时候,
把AnnotationAwareAspectJAutoProxyCreator封装成BeanDefinition,对应的key=internalAutoProxyCreator;
@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { // 把AnnotationAwareAspectJAutoProxyCreator封装成一个BeanDefinition; return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
【(一)AOP 如何注入SpringBoot中()】
文章图片
InitializeBean -- 初始化bean的时候,会统一调用所有的BeanPostProcessor.postProcessAfterInitialization;其中就会调用到AnnotationAwareAspectJAutoProxyCreator;进行查看是否有符合要求的切面方法;
调用方法如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
......// 重点如下:找到这个bean的所有切面方法,然后调用createProxy创建代理类;返回即可。
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
1.3 找所有的合适的通知
protected List findEligibleAdvisors(Class> beanClass, String beanName) {
// 1 找到所有的候选通知
List candidateAdvisors = findCandidateAdvisors();
// 2 进行匹配,查看是否合适
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 3 这里排序Advisor?
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
1.3.1 findCandidateAdvisors
protected List findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 从所有带@Advisor注解的切面类;
List advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 开始找@AspectJ的注解类;advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
主要逻辑:
- 遍历BeanDefinitionMap,查看是否有@AspectJ注解,
- 如果有,则会遍历method,查看是否是一个通知,如果是一个通知,则会封装成一个InstantiationModelAwarePointcutAdvisorImpl类;
- 然后封装返回;
在这个方法里面还有一个排序!! 在getAdvisorMethod中
private List
getAdvisorMethods(Class> aspectClass) { List methods = new ArrayList<>(); ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter); if (methods.size() > 1) { methods.sort(adviceMethodComparator); } return methods; }
private static final Comparator adviceMethodComparator;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
// an @After advice method will actually be invoked after @AfterReturning and
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
// invokes proceed() in a `try` block and only invokes the @After advice method
// in a corresponding `finally` block.
Comparator adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter) method -> {
AspectJAnnotation> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator methodNameComparator = new ConvertingComparator<>(Method::getName);
adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}
我们发现,他是按照Around、Before、After、AfterReturning进行排序,如果有相同,则按照methodName进行排序;
1.3.2 findAdvisorsThatCanApply 查看这个类是否和PointCut 匹配成功,匹配成功,即返回列表;
protected List findAdvisorsThatCanApply(
List candidateAdvisors, Class> beanClass, String beanName) {ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 查看这个类是否和PointCut 匹配成功,匹配成功,即ok;
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
1.3.3 findAdvisorsThatCanApply 比较两个类的order大小;
1.4 createProxy 这个不在细追,
主题逻辑:
- 找到所有的Advisor
- 创建指定的拦截器,比如:dynamicAdvisorInterceptor加入到callback方法中;
- Enhancer.create();
- 先想好,再去做;
- 命名艺术,AutoProxyCreator、AspectJAdvisor、AspectJAdvisorBuilder、XXFactory
- 封装成对象,便于以后的扩展
推荐阅读
- Java每日一练|Java语言每日一练—第9天(根据输入的数据判断是星期几)
- Java每日一练|Java基础每日一练—第8天(判断大小)
- JavaSE系列详解|新星计划day4【Java语言IO流】缓冲流的详解
- Java每日一练|Java基础每日一练—第7天(最优选择)
- JavaSE系列详解|Java基础IO流之序列化流的使用
- JavaSE系列详解|Java基础IO流之字符流的使用
- CSY-java后端学习目录
- 零碎知识|springboot项目的zip发版转为jar包发版所得
- 笔记|疫情防控交流社区平台——5.1 Kafka构建TB级异步消息系统(发送系统通知)