spring源码---Aop:解析@Aspect
我们知道@Aspect的解析,发生在BeanFactoryAspectJAdvisorsBuilder类中,那么这个类是何方神圣呢?
它在注解中写道:帮助@Aspecj bean from BeanFactory 进行解析,并且建立Advisors。用来auto -proxying。
1.初始化:
在AbstractAutoProxyCreator在refresh()第六步中进行getBean(),注入到BeanPostProcessor容器中的时候,进行了实例化and初始化,而它的子类的初始化方法:
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory{
this.beanFactory = beanFactory;
this.advisorFactory = advisorFactory;
}
这里就new了一个builder,传入的参数,重点是第二个:ReflectiveAspectJAdvisorFactory类:
结构简单:
2.成员:
private final ListableBeanFactory beanFactory;
//advisos解析助手
private final AspectJAdvisorFactory advisorFactory;
private volatile List<String> aspectBeanNames;
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>();
它的字段存放了BeanFactory,还存放了解析的AspectJ bean,还有对于的Advisor,我们这里重点就是通过AdvisorFactory如何解析出Advisor,这里先看一下什么是Advisor:
Advice:对应增强的方法 参考:https://www.jianshu.com/p/6c1b73b54c46
Advisor:关联了Advice和Pointcut。上起到了连接点的匹配下起到了通知类型的调用。统一了拦截的调用过程。
Advised:关联了Advisor和TargetSource的类。AOP进行方法拦截的时候,就是从它里面获取的拦截调用链。
单词:advice 通知,建议 advisor 顾问
它在本类中使用的实现类:InstantiationModelAwarePoincutAdvisorImpl类
它的字段丰富:
private final AspectJExpressionPointcut declaredPointcut;
private final Class<?> declaringClass;
//代表一个方法,方法的数据信息
private final String methodName;
private final Class<?>[] parameterTypes;
private transient Method aspectJAdviceMethod;
//两个工厂
private final AspectJAdvisorFactory aspectJAdvisorFactory;
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
private final int declarationOrder;
private final String aspectName; //@Aspect通知类的名字
private final Pointcut pointcut; //联系Pointcut
private final boolean lazy;
private Advice instantiatedAdvice; //联系Advice
private Boolean isBeforeAdvice;
private Boolean isAfterAdvice;
3.解析过程:
在builder的build()方法中核心部分:
if (this.advisorFactory.isAspect(beanType)) { //找到@Aspect 注解的bean
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//封装
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//获得 类中的方法 【入】
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
advisors.addAll(classAdvisors);
}
可见调用advisorFactory进行解析:传入的是BeanFactory和beanName的封装,里面解析出了AspectMetadata信息,在这个类构造的时候进行解析的。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
//再一次封装
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//解析获得Advisor
for (Method method : getAdvisorMethods(aspectClass)) { //获得所有方法,除去@pointcut
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); //【入】
if (advisor != null) {
advisors.add(advisor);
}
}
//advisors为空
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 处理@Aspect中的字段
@DeclareParents的使用:https://www.jianshu.com/p/f7238613c877
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
在解析过程中,对于普通method来说,解析比较简单,封装成advice即可,而对于pointcut的解析,稍显复杂,所以我们重点放在了pointcut的解析上面。
1.getAdvisorMethods()
排除掉@pointcut方法,剩下本类的方法,+Object定义的很多方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
//如果不是@Pointcut方法,则添加
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
});
methods.sort(METHOD_COMPARATOR);
return methods;
}
使用doWithMethods()对方法进行遍历,然后设置回调函数,并且要遍历父类的方法,递归调用:
public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
}
try {
mc.doWith(method); //回调--> 保存method
}
}
if (clazz.getSuperclass() != null) {
doWithMethods(clazz.getSuperclass(), mc, mf); //递归父类
}
else if (clazz.isInterface()) { //接口
for (Class<?> superIfc : clazz.getInterfaces()) {
doWithMethods(superIfc, mc, mf);
}
}
}
2.getAdvisor()【重点】
对方法进行遍历处理,
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//获取 切点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//查看返回的类型,也就是Advisor的实现类
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
【注意】这里传入的是任何method,除了pointcut方法,那么这里的获取切点 表达式,并不是实际的切点表达式,而是5个通知标签里面的value,该value指名了使用那个切点。
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); //找AspectJAnnotation注解
if (aspectJAnnotation == null) {
return null;
}
//创建
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); //设置表达式
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
findAspectJAnnotationOnMethod(),观察这个方法,是否实现了集合中的某个注解,找到了就封装返回。
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) { //集合,装了6个注解
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
//上述的常量集合:
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
跟入(跳过一级):find(),调用工具类进行find
public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType) {
Assert.notNull(method, "Method must not be null");
if (annotationType == null) {
return null;
}
//先从缓存中获取
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
A result = (A) findAnnotationCache.get(cacheKey);
//缓存未击中
if (result == null) {
//解析 是否是桥接方法,
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
//find
result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType); //【入】
if (result == null) {
result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
}
Class<?> clazz = method.getDeclaringClass();
while (result == null) { //遍历父类
....
}
if (result == null) {
result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
}
}
if (result != null) {
result = synthesizeAnnotation(result, method); //桥接方法处理
findAnnotationCache.put(cacheKey, result); //保存
}
}
return result;
}
BridgedMethod:https://www.jianshu.com/p/250030ea9b28
其实就是一个反射就搞定了,搞这么麻烦,主要是情况没有找到的情况下,还需要处理什么父类等等情况,确保不漏掉。
现在找到了point 表达式,其实不仅仅是找表达式,还有判断method,是否存在五个通知的注解,再从五个通知里面找到表达式,也就是注解的value值。
现在找到了开始封装advisor
回到ReflectiveAspectJAdvisorFactory类的getAdvisor()方法:
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
//构造方法片段:
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); //【入】
}
,pointcut表达式,只是简单的保存,没有处理,重点是生成advice类,看一下它的五个实现
instaniateAdvice进入:
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
//【入】
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
//getAdvice:
....
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
.... 五个通知
现在advisor创建完毕。注意PointCut()真实的注解,在这里是没有解析的,也就是说真实的切入点注解并没有解析出来,要等到后面bean,afterBeanPostProcessor()被触发继续分析。
本文地址:https://blog.csdn.net/W1427259949/article/details/108039063
上一篇: 优酷视频下载失败总是出错该怎么办呢?
下一篇: Java语法深入理解之泛型
推荐阅读
-
【spring-boot 源码解析】spring-boot 依赖管理
-
【spring-boot 源码解析】spring-boot 依赖管理梳理图
-
spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)
-
Spring5源码解析5-ConfigurationClassPostProcessor (上)
-
spring5 源码深度解析----- AOP代理的生成
-
Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
-
源码解析Spring 数据库异常抽理知识点总结
-
spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
-
Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析
-
基于Spring注解的上下文初始化过程源码解析(一)