Aspectj与Spring AOP比较参考:https://www.jianshu.com/p/872d3dbdc2ca
XML配置方式
:定义切面, 包括通知和切点. 是一般的bean
定义通知器, 跟切面一样,也包括通知(advice)和切点(PointCut) . 通知必须实现Advice接口.
基本概念
(通知、切面):某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
(连接点):程序运行中的某个阶段点,比如方法的调用、异常的抛出等。
(切入点): JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
(增强): PointCut 和 Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。
(切面): 通常是一个类的注解,类中可以定义切入点和通知
:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类。
Pointcut
表示式(expression)和签名(signature)
由下列方式来定义或者通过 &&、 ||、 !、 的方式进行组合:
:匹配 方法执行的连接点;
: 目标对象target的类型是否和within中指定的类型匹配 。参数可指定包路径或具体的类全路径名。
匹配原则:target.getClass().equals(within表达式中指定的类型)
: 通过aop创建的代理对象的类型是否和this中指定的类型匹配;注意判断的目标是代理对象;this中使用的表达式必须是类型全限定名,不支持通配符。
匹配原则:this(x),则代理对象proxy满足下面条件时会匹配: x.getClass().isAssignableFrom(proxy.getClass());
: 判断目标对象的类型是否和指定的类型匹配;注意判断的目标是实际对象的类型;表达式必须是类型全限定名,不支持通配符。
匹配原则: target(x),则目标对象target满足下面条件时会匹配 x.getClass().isAssignableFrom(target.getClass());
:匹配 当前执行的方法传入的参数为指定类型的执行方法;
:自定义注解标注在类上,该类的所有方法(不包含子类方法)执行aop方法
:匹配 当前目标对象类型的执行方法,其中目标对象类持有指定的注解;
:当前执行的方法传入的参数持有指定注解;
:匹配 执行方法持有指定注解;
格式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)其中后面跟着“?”的是可选项
括号中各个pattern分别表示:
修饰符匹配(modifier-pattern?)
返回值匹配(ret-type-pattern): 可以为*表示任何返回值, 全路径的类名等
类路径匹配(declaring-type-pattern?)
方法名匹配(name-pattern):可以指定方法名 或者 *代表所有,set* 代表以set开头的所有方法
参数匹配((param-pattern)):可以指定具体的参数类型。多个参数间用“,”隔开,各个参数也可以用"*" 来表示匹配任意类型的参数,".."表示零个或多个任意参数。
eg. (String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型。
异常类型匹配(throws-pattern?)
任意公共方法的执行:execution(public * *(..))
任何一个以“set”开始的方法的执行:execution(* set*(..))
AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))
定义在service包和所有子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
第一个*表示匹配任意的方法返回值, ..(两个点)表示零个或多个,第一个..表示service包及其子包,第二个*表示所有类, 第三个*表示所有方法,第二个..表示方法的任意参数个数
定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)
pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)
实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)
当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型
带有@Transactional标注的所有类的任意方法:
JoinPoint
@Before: 标识一个前置增强方法.
@After:final增强,不管是抛出异常或者正常退出都会执行.
@AfterReturning: 后置增强,方法正常退出时执行.
@AfterThrowing: 异常抛出增强.
@Around: 环绕增强.
常用的方法:
Object[] getArgs:返回目标方法的参数
Signature getSignature():返回目标方法的签名信息。可获取方法名等
Object getTarget():返回被织入增强处理的目标对象
Object getThis():返回AOP框架为目标对象生成的代理对象
使用处理时,需要将第一个参数定义为类型才可使用方法。
因为在 里默认为false; 而重写为true;
Causedby:java.lang.IllegalArgumentException:ProceedingJoinPointisonlysupportedforaroundadvice
atorg.springframework.aop.aspectj.AbstractAspectJAdvice.maybeBindProceedingJoinPoint(AbstractAspectJAdvice.java:414)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.AbstractAspectJAdvice.calculateArgumentBindings(AbstractAspectJAdvice.java:388)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvice(ReflectiveAspectJAdvisorFactory.java:294)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.instantiateAdvice(InstantiationModelAwarePointcutAdvisorImpl.java:149)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl.(InstantiationModelAwarePointcutAdvisorImpl.java:113)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisor(ReflectiveAspectJAdvisorFactory.java:198)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.getAdvisors(ReflectiveAspectJAdvisorFactory.java:126)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors(BeanFactoryAspectJAdvisorsBuilder.java:110)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:95)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:101)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:251)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1124)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:1097)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:504)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
... 15commonframesomitted
模块中: 提供支持的是给 使用的
模块中:根本上是一个
织入
表达式中增加了args(time, name)部分,意味着可以在增强处理的签名方法(access方法)中定义"time"和"name"两个同名属性。这两个形参的类型由access方法同名参数类型指定。一旦指定了, 则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为String的方法(方法参数个数和类型若有不同均不匹配);
access方法只需要满足"time", "name"参数的顺序和pointcut中args(time, name)的顺序相同即可,"returnValue"位置顺序无所谓。
eg.
执行顺序
正常情况执行结果:
aroundbegin
before
目标方法testAdvice
aroundafter
after
afterReturning
有异常情况下:
aroundbegin
before
目标方法testAdvice
aroundafterexception
after
afterThrowing
测试过程中发现,debug模式下可知JoinPoint的实际类型是(before、around 都是该实际类型)
但若代码直接写定该类型,启动报错
Causedby:java.lang.IllegalArgumentException:errorat::0formalunboundinpointcut
atorg.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:319)~[aspectjweaver-1.9.4.jar:na]
atorg.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:227)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.AspectJExpressionPointcut.obtainPointcutExpression(AspectJExpressionPointcut.java:198)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:177)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.support.AopUtils.canApply(AopUtils.java:225)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.support.AopUtils.canApply(AopUtils.java:288)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:320)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:126)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:95)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:76)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299)~[spring-aop-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:429)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)~[spring-beans-5.1.7.RELEASE.jar:5.1.7.RELEASE]
因为, 执行到时:对与是不用额外处理参数绑定。
所以被当作额外的参数。
后续先执行进入:
创建参数类型绑定关系。
接着执行进入:
首先 来根据实际情况解析该绑定关系;接着执行校验方法因真实绑定为空,判定失败后异常
同一个方法被多个Aspect类拦截
优先级高的切面类里的增强处理 优先于 优先级低的切面类。
在“进入”连接点时,最高优先级的增强处理将先被织入(eg. 给定的两个不同切面类Before增强处理中,优先级高的那个会先执行);
在“退出”连接点时,最高优先级的增强处理会最后被织入(eg. 给定的两个不同切面类After增强处理中,优先级高的那个会后执行)。
eg. 优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入。
Spring提供了如下两种解决方案指定不同切面类里的增强处理的优先级:
同一个切面类里的两个相同类型的增强处理在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,没有办法指定它们的织入顺序。即使给这两个 advice 添加了 @Order 这个注解,也不行!
喜欢,在看
领取专属 10元无门槛券
私享最新 技术干货