AOP源码解析(三)增强器的获取
来源:互联网 发布:cc域名注册哪里便宜 编辑:程序博客网 时间:2024/06/07 00:55
普通增强器的获取逻辑通过getAdvisor方法实现,实现步骤包括对切点的注解的获取及根据注解信息生成增强。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) { validate(aif.getAspectMetadata().getAspectClass()); //切点信息的获取 AspectJExpressionPointcut ajexp = getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass()); if(ajexp == null) return null; else //根据切点信息生成增强器 return new InstantiationModelAwarePointcutAdvisorImpl(this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName); }
(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("test()")
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class candidateAspectClass) { //获取方法上的注解 AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if(aspectJAnnotation == null) { return null; } else { //使用AspectJExpressionPointcut实例封装获取的信息 AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]); //提取得到的注解中的表达式如:@Pointcut("execution(* *.*test*(..))")中的execution(* *.*test*(..))<pre name="code" class="java">
))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); return ajexp; } }
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) { //设置敏感的注解类 Class classesToLookFor[] = { org/aspectj/lang/annotation/Before, org/aspectj/lang/annotation/Around, org/aspectj/lang/annotation/After, org/aspectj/lang/annotation/AfterReturning, org/aspectj/lang/annotation/AfterThrowing, org/aspectj/lang/annotation/Pointcut }; for(Class<? extends Annotation> c : classsesToLookFor) { AspectJAnnotation foundAnnotation = findAnnotation(method, c); if(foundAnnotation != null) return foundAnnotation; } return null; }//获取指定方法上的注解并使用AspectJAnnotation封装
private static AspectJAnnotation findAnnotation(Method method, Class toLookFor) { Annotation result = AnnotationUtils.findAnnotation(method, toLookFor); if(result != null) return new AspectJAnnotation(result); else return null; }(2)根据切点信息生成增强。所有的增强都有Advisor实现类InstantiationModelAwarePontcutAdvisorImpl统一疯长。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { declaredPointcut = ajexp; this.method = method; atAspectJAdvisorFactory = af; aspectInstanceFactory = aif; declarationOrder = declarationOrderInAspect; this.aspectName = aspectName; if(aif.getAspectMetadata().isLazilyInstantiated()) { Pointcut preInstantiationPointcut = Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), declaredPointcut); pointcut = new PerTargetInstantiationModelPointcut(declaredPointcut, preInstantiationPointcut, aif); lazy = true; } else { instantiatedAdvice = instantiateAdvice(declaredPointcut); pointcut = declaredPointcut; lazy = false; } }
封装过程只是简单地将信息封装在类的实例中,所有的额信息单纯地复制。在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before(“test()”)与After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的额增强器就是在instantiateAdvice函数中实现的。
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) { return atAspectJAdvisorFactory.getAdvice(method, pcut, aspectInstanceFactory, declarationOrder, aspectName); }
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) { Class candidateAspectClass = aif.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if(aspectJAnnotation == null) return null; //if we get here,we know we have an AspectJ method. Check that its an AspectJ-annotated class if(!isAspect(candidateAspectClass)) throw new AopConfigException((new StringBuilder()).append("Advice must be declared inside an aspect type: Offending method '").append(candidateAdviceMethod).append("' in class [").append(candidateAspectClass.getName()).append("]").toString()); if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Found AspectJ method: ").append(candidateAdviceMethod).toString()); AbstractAspectJAdvice springAdvice; switch(_cls4..SwitchMap.org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationType[aspectJAnnotation.getAnnotationType().ordinal()]) { case 1: // '\001' springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif); break; case 2: // '\002' springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif); break; case 3: // '\003' springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif); AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation(); if(StringUtils.hasText(afterReturningAnnotation.returning())) springAdvice.setReturningName(afterReturningAnnotation.returning()); break; case 4: // '\004' springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif); AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation(); if(StringUtils.hasText(afterThrowingAnnotation.throwing())) springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); break; case 5: // '\005' springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif); break; case 6: // '\006' if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Processing pointcut '").append(candidateAdviceMethod.getName()).append("'").toString()); return null; default: throw new UnsupportedOperationException((new StringBuilder()).append("Unsupported advice type on method ").append(candidateAdviceMethod).toString()); } springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrderInAspect); String argNames[] = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if(argNames != null) springAdvice.setArgumentNamesFromStringArray(argNames); springAdvice.calculateArgumentBindings(); return springAdvice; } }从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如AtBefore会对应AspectJMethodBeforeAdvice。
2.增加同步实例化增强器
如果寻找的增强器不为空而且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器。同步实例化增强器SyntheticInstantiationAdvisor,如下:
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor { public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) { super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() { //目前方法前调用,类似@Before public void before(Method method, Object args[], Object target) { //简单初始化aspect aif.getAspectInstance(); }
3.获取DeclareParents注解
DeclareParents主要用于引介增强的注解形式的实现,而其实现方式驭普通增强很类似,只不过使用DeclareParentsAdvisor对功能进行封装。
private Advisor getDeclareParentsAdvisor(Field introductionField) { DeclareParents declareParents = (DeclareParents)introductionField.getAnnotation(org/aspectj/lang/annotation/DeclareParents); if(declareParents == null) return null; if(org/aspectj/lang/annotation/DeclareParents.equals(declareParents.defaultImpl())) throw new IllegalStateException("defaultImpl must be set on DeclareParents"); else return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }后面一节我们一起分析一下,Spring如何寻找匹配的增强器,篇幅较长,也比较复杂,但还是希望我们一起看下去,因为这个过程虽然很艰辛,坚持过后,你会发现,收获是非常巨大的。
0 0
- AOP源码解析(三)增强器的获取
- AOP源码解析(四)寻找匹配的增强器
- Spring源码学习笔记(四)-Aop获取增强、切点
- Spring源码阅读(六)—AOP获取增强
- AOP源码解析(五)获取代理
- aop源码解析三-postProcessAfterInitialization
- Spring AOP的实现原理之获取增强器Adivors
- Spring基于注解形式的 AOP的原理流程及源码解析(三)
- Spring AOP源码解读2 - 切面和增强的取得
- Spring源码解析之-Aop源码解析(2)
- spring源码解析-Aop
- Spring源码解析-aop
- Spring源码解析-AOP
- AOP源码解析(二)创建AOP代理
- 理解Spring AOP 原理(三)Spring AOP 源码分析
- 做一个合格的程序猿之浅析Spring AOP源码(十八) Spring AOP开发大作战源码解析
- Spring AOP(三)之AfterThrowing增强处理
- Spring源码分析:AOP源码解析(上篇)
- python 制作小蛇
- [LeetCode416]Partition Equal Subset Sum
- displaytag添加自定义跳转页数功能
- C/C++笔试必须熟悉掌握的头文件系列(七)——cctype/ctype.h
- C++笔记
- AOP源码解析(三)增强器的获取
- c语言学习总结之从关键字到循环结构
- python3报错解决办法:UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal multib
- 嵌入式开发为什么选择C语言?
- Binary Tree_build & travserse(二叉树建立,遍历)
- (十二)java多线程之Exchanger
- 机器学习(十)使用sklearn库对时间特征进行处理
- 第九周 OJ-5年月日
- 梯度下降法