前言
会更新AOP 系列源码文章 主要更新目录
篇幅问题 会分章程更新
注解原理
@EnableAspectJAutoProxy:AOP 注解驱动,给容器中导入 AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
// 是否强制使用 CGLIB 创建代理对象
// 配置文件方式:<aop:aspectj-autoproxy proxy-target-class="true"/>
boolean proxyTargetClass() default false;
// 将当前代理对象暴露到上下文内,方便代理对象内部的真实对象拿到代理对象
// 配置文件方式:<aop:aspectj-autoproxy expose-proxy="true"/>
boolean exposeProxy() default false;
}
AspectJAutoProxyRegistrar 在用来向容器中注册 AnnotationAwareAspectJAutoProxyCreator,以 BeanDefiantion 形式存在,在容器初始化时加载。AnnotationAwareAspectJAutoProxyCreator 间接实现了 InstantiationAwareBeanPostProcessor,Order 接口,该类会在 Bean 的实例化和初始化的前后起作用
工作流程:创建 IOC 容器,调用 refresh() 刷新容器,registerBeanPostProcessors(beanFactory) 阶段,通过 getBean() 创建 AnnotationAwareAspectJAutoProxyCreator 对象,在生命周期的初始化方法中执行回调 initBeanFactory() 方法初始化注册三个工具类:BeanFactoryAdvisorRetrievalHelperAdapter、ReflectiveAspectJAdvisorFactory、BeanFactoryAspectJAdvisorsBuilderAdapter
后置处理
Bean 初始化完成的执行后置处理器的方法:
public Object postProcessAfterInitialization(@Nullable Object bean,String bN){
if (bean != null) {
// cacheKey 是 【beanName 或者加上 & 的 beanName】
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 去提前代理引用池中寻找该 key,不存在则创建代理
// 如果存在则证明被代理过,则判断是否是当前的 bean,不是则创建代理
return wrapIfNecessary(bean, bN, cacheKey);
}
}
return bean;
}
AbstractAutoProxyCreator.wrapIfNecessary():根据通知创建动态代理,没有通知直接返回原实例
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 条件一般不成立,很少使用 TargetSourceCreator 去创建对象 BeforeInstantiation 阶段,doCreateBean 之前的阶段
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// advisedBeans 集合保存的是 bean 是否被增强过了
// 条件成立说明当前 beanName 对应的实例不需要被增强处理,判断是在 BeforeInstantiation 阶段做的
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 条件一:判断当前 bean 类型是否是基础框架类型,这个类的实例不能被增强
// 条件二:shouldSkip 判断当前 beanName 是否是 .ORIGINAL 结尾,如果是就跳过增强逻辑,直接返回
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 【查找适合当前 bean 实例的增强方法】(下一节详解)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 条件成立说明上面方法查询到适合当前class的通知
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根据查询到的增强创建代理对象(下一节详解)
// 参数一:目标对象
// 参数二:beanName
// 参数三:匹配当前目标对象 clazz 的 Advisor 数据
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 保存代理对象类型
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象
return proxy;
}
// 执行到这里说明没有查到通知,当前 bean 不需要增强
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// 【返回原始的 bean 实例】
return bean;
}
获取通知
AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean():查找适合当前类实例的增强,并进行排序
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查询适合当前类型的增强通知
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
// 增强为空直接返回 null,不需要创建代理
return DO_NOT_PROXY;
}
// 不是空,转成数组返回
return advisors.toArray();
}
属性解读
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors():
-
candidateAdvisors = findCandidateAdvisors():获取当前容器内可以使用(所有)的 advisor,调用的是 AnnotationAwareAspectJAutoProxyCreator 类的方法,每个方法对应一个 Advisor-
advisors = super.findCandidateAdvisors():查询出 XML 配置的所有 Advisor 类型advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors():通过 BF 查询出来 BD 配置的 class 中 是 Advisor 子类的 BeanNameadvisors.add():使用 Spring 容器获取当前这个 Advisor 类型的实例
-
advisors.addAll(....buildAspectJAdvisors()):获取所有添加 @Aspect 注解类中的 AdvisorbuildAspectJAdvisors():构建的方法,把 Advice 封装成 Advisor-
beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false):获取出容器内 Object 所有的 beanName,就是全部的 -
for (String beanName : beanNames):遍历所有的 beanName,判断每个 beanName 对应的 Class 是否是 Aspect 类型,就是加了 @Aspect 注解的类-
factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName):使用工厂模式管理 Aspect 的元数据,关联的真实 @Aspect 注解的实例对象 -
classAdvisors = this.advisorFactory.getAdvisors(factory):添加了 @Aspect 注解的类的通知信息-
aspectClass:@Aspect 标签的类的 class
-
for (Method method : getAdvisorMethods(aspectClass)):遍历不包括 @Pointcut 注解的方法Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName):将当前 method 包装成 Advisor 数据-
AspectJExpressionPointcut expressionPointcut = getPointcut():获取切点表达式 -
return new InstantiationModelAwarePointcutAdvisorImpl():把 method 中 Advice 包装成 Advisor,Spring 中每个 Advisor 内部一定是持有一个 Advice 的,Advice 内部最重要的数据是当前 method 和aspectInstanceFactory,工厂用来获取实例this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut):实例化 Advice 对象,逻辑是获取注解信息,根据注解的不同生成对应的 Advice 对象
-
-
-
advisors.addAll(classAdvisors):保存通过 @Aspect 注解定义的 Advisor 数据
-
-
this.aspectBeanNames = aspectNames:将所有 @Aspect 注解 beanName 缓存起来,表示提取 Advisor 工作完成 -
return advisors:返回 Advisor 列表
-
-
-
eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, ...):选出匹配当前类的增强-
if (candidateAdvisors.isEmpty()):条件成立说明当前 Spring 没有可以操作的 Advisor -
List<Advisor> eligibleAdvisors = new ArrayList<>():存放匹配当前 beanClass 的 Advisors 信息 -
for (Advisor candidate : candidateAdvisors):遍历所有的 Advisorif (canApply(candidate, clazz, hasIntroductions)):判断遍历的 advisor 是否匹配当前的 class,匹配就加入集合-
if (advisor instanceof PointcutAdvisor):创建的 advisor 是 InstantiationModelAwarePointcutAdvisorImpl 类型PointcutAdvisor pca = (PointcutAdvisor) advisor:封装当前 Advisorreturn canApply(pca.getPointcut(), targetClass, hasIntroductions):重载该方法-
if (!pc.getClassFilter().matches(targetClass)):类不匹配 Pointcut 表达式,直接返回 false -
methodMatcher = pc.getMethodMatcher():获取 Pointcut 方法匹配器,类匹配进行类中方法的匹配 -
Set<Class<?>> classes:保存目标对象 class 和目标对象父类超类的接口和自身实现的接口 -
if (!Proxy.isProxyClass(targetClass)):判断当前实例是不是代理类,确保 class 内存储的数据包括目标对象的class 而不是代理类的 class -
for (Class<?> clazz : classes):检查目标 class 和上级接口的所有方法,查看是否会被方法匹配器匹配,如果有一个方法匹配成功,就说明目标对象 AOP 代理需要增强specificMethod = AopUtils.getMostSpecificMethod(method, targetClass):方法可能是接口的,判断当前类有没有该方法return (specificMethod != method && matchesMethod(specificMethod)):类和方法的匹配,不包括参数
-
-
-
-
extendAdvisors(eligibleAdvisors):在 eligibleAdvisors 列表的索引 0 的位置添加 DefaultPointcutAdvisor,封装了 ExposeInvocationInterceptor 拦截器 -
eligibleAdvisors = sortAdvisors(eligibleAdvisors):对拦截器进行排序,数值越小优先级越高,高的排在前面- 实现 Ordered 或 PriorityOrdered 接口,PriorityOrdered 的级别要优先于 Ordered,使用 OrderComparator 比较器
- 使用 @Order(Spring 规范)或 @Priority(JDK 规范)注解,使用 AnnotationAwareOrderComparator 比较器
- ExposeInvocationInterceptor 实现了 PriorityOrdered ,所以总是排在第一位,MethodBeforeAdviceInterceptor 没实现任何接口,所以优先级最低,排在最后
-
return eligibleAdvisors:返回拦截器链
结尾
后置处理 算是AOP的第一步理解 需要大概有点AOP思想基础才能 看明白系列文章
本文正在参加「金石计划 . 瓜分6万现金大奖」