Spring-AOP @AspectJ语法基础
2017-08-25 11:09
549 查看
概述
切点表达式函数
方法切点函数
execution
annotation
方法入参切点函数
args
args
目标类切点函数
within
target
within
target
代理类切点函数
this
注意事项
在函数入参中使用通配符
支持通配符的函数说明
逻辑运算符
不同增强类型
Before
AfterReturning
Around
AfterThrowing
After
DeclareParents
引介增强用法
下文阐述的AspectJ切点表达式语言,以AspectJ5.0版本为准。
比如
在这里execution代表目标类执行某一方法,而 * greetTo(..)描述目标方法的匹配模式串,二者联合起来标识目标类greetTo()方法的连接点。 为了方便描述,将
Spring支持9个@AspectJ切点表达式函数,它们用不同的方式描述目标类的连接点
根据描述对象的不同,大致可以分为4类
方法切点函数:通过描述目标类方法的信息定义连接点
方法入参切点函数:通过描述目标类方法入参的信息定义连接点
目标类切点函数:通过描述目标类类型的信息定义连接点
代理类切点函数:通过描述目标类的代理类的信息定义连接点
下面我们来看下具体的函数
说明:表示满足某一匹配模式的所有目标类方法连接点,如 execution(* greetTo(..))表示所有目标类中的greetTo()方法,greetTo()方法可以带带任意的入参和任意的返回值
说明:表示标注了某特定注解的目标类方法连接点, 比如@annotation(com.xgj.annotation.NeedTest)表示任何标注了@NeedTest注解的目标类方法。
说明:通过判断目标类方法运行时入参对象的类型定义指定连接点,如args(com.xgj.Waiter)表示所有有且仅有一个按类型匹配于Waiter入参的方法。
说明:通过判断目标类方法运行时入参对象的类是否标注了特定的注解指定连接点。 比如@args(com.xgj.Monitor)表示任何这样的一个目标方法,它有一个入参且入参对象的类标注@Monitor注解
说明:表示特定域下的所有连接点,比如
说明:假如目标类按类型匹配与指定类,则目标类的所有连接点匹配这个切点。 比如通过target(com.xgj.Waiter)定义的切点,Waiter及Waiter实现类NaiveWaiter中的所有连接点都匹配该切点
说明:假如目标类按类型匹配于某个类A,且类A标注了特定的注解,这目标类的所有连接点匹配这个切点。 比如@within(com.xgj.Monitor)定义的切点,加入Waiter实现了@Monitor注解,这Waiter及Waiter的实现类NaiveWaiter的说哟连接点都匹配这个切点
说明:假如目标类标注了特定注解,则目标类的所有连接点都匹配该切点。 如@target(com.xgj.Monitor),假设NaiveWaiter标注了@Monitor注解,则NaiveWaiter的所有连接点都匹配这个切点
说明:代理类按类型匹配于指定类,则被代理的目标类的所有连接点都匹配该切点。
仅支持“+”通配符: args()、this()和target(). 比如args(com.xgj.Waiter+) 、target(java.util.List+)等。 虽然支持+通配符,但是意义不大。 对于这些函数来讲使用+和不使用+是等价的
不支持通配符: @args()、@within、@target 和 @annotation.
此外,args() this() target() @args() @within() @target() @annotation() 这7个函数除了可以指定类名外,也可以指定变量名,并将目标对象中的变量绑定到增强的方法中。
Spring支持以下切点运算符
如果在Spring的XML配置文件中使用切点表达式,由于&是XML特殊字符,所以使用转义字符串
为了方便,Spring提供了一个等效的运算符and, 比如
注意:
在Spring中使用and or 和 not操作符时,允许不在前面添加空格,比如
另外,如果not位于切点表达式的开头,则必须在开头添加一个空格,否则会产生解析错误。 比如
此外,这些注解的存留期限都是RetentionPolicy.RUNTIME,标注目标都是ElementType.METHOD。
Before注解类拥有两个成员:
value:该成员用于定义切点;
argNames:由于无法通过Java反射机制获取方法入参名,所有如果在Java编译时未启动调试信息或者需要在运行期解析切点,就必须通过这个成员指定注解所标注增强方法的参数名(注意两者名字必须完全相同),多个参数名用逗号分隔。
AfterReturning注解类拥有4个成员:
value:该成员用于定义切点;
pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
returning:将目标对象方法的返回值绑定给增强的方法;
argNames:如前所述。
Around注解类拥有两个成员:
value:该成员用于定义切点;
argNames:如前所述。
AfterThrowing注解类拥有4个成员:
value:该成员用于定义切点;
pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
throwing:将抛出的异常绑定到增强方法中;
argNames:如前所述。
After注解类拥有两个成员:
value:该成员用于定义切点;
argNames:如前所述。
DeclareParents注解类拥有两个成员:
value:该成员用于定义切点,它表示在哪个目标类上添加引介增强;
defaultImpl:默认的接口实现类。
假设我们希望Waiter能够同时充当Seller的角色,即通过切面技术为NaiveWaiter新增Seller接口的实现。
下面我们使用@AspectJ的引介增强来实现这一个功能。
分析:
在EnableSellerAspect 切面中,通过@DeclareParents为NaiveWaiter添加了一个需要实现的Seller接口,并指定其默认实现类为SmartSeller. 然后通过切面技术将SmartSeller融合到NaiveWaiter中,这样NaiveWaiter就实现了Seller接口。
配置文件,配置切面和NaiveWaiter Bean
测试类:
运行结果:
可见,NaiveWaiter已经成功的新增了Seller接口的实现。
切点表达式函数
方法切点函数
execution
annotation
方法入参切点函数
args
args
目标类切点函数
within
target
within
target
代理类切点函数
this
注意事项
在函数入参中使用通配符
支持通配符的函数说明
逻辑运算符
不同增强类型
Before
AfterReturning
Around
AfterThrowing
After
DeclareParents
引介增强用法
概述
@AspectJ使用Java5.0注解和正规的AspectJ的切点表达式语言描述切面, 由于Spring只支持方法的连接点,所以Spring仅支持部分AspectJ的切点语言。下文阐述的AspectJ切点表达式语言,以AspectJ5.0版本为准。
切点表达式函数
AspectJ5.0的切点表达式由关键字和操作参数组成.比如
execution(* greetTo(..)),
execution为关键字,
* greetTo(..)为操作参数。
在这里execution代表目标类执行某一方法,而 * greetTo(..)描述目标方法的匹配模式串,二者联合起来标识目标类greetTo()方法的连接点。 为了方便描述,将
execution()称为函数,而将匹配串
* greetTo(..)称作函数的入参。
Spring支持9个@AspectJ切点表达式函数,它们用不同的方式描述目标类的连接点
根据描述对象的不同,大致可以分为4类
方法切点函数:通过描述目标类方法的信息定义连接点
方法入参切点函数:通过描述目标类方法入参的信息定义连接点
目标类切点函数:通过描述目标类类型的信息定义连接点
代理类切点函数:通过描述目标类的代理类的信息定义连接点
下面我们来看下具体的函数
方法切点函数
execution()
入参:方法匹配模式串说明:表示满足某一匹配模式的所有目标类方法连接点,如 execution(* greetTo(..))表示所有目标类中的greetTo()方法,greetTo()方法可以带带任意的入参和任意的返回值
@annotation()
入参:方法注解类名说明:表示标注了某特定注解的目标类方法连接点, 比如@annotation(com.xgj.annotation.NeedTest)表示任何标注了@NeedTest注解的目标类方法。
方法入参切点函数
args()
入参:类名说明:通过判断目标类方法运行时入参对象的类型定义指定连接点,如args(com.xgj.Waiter)表示所有有且仅有一个按类型匹配于Waiter入参的方法。
@args()
入参:类型注解类型说明:通过判断目标类方法运行时入参对象的类是否标注了特定的注解指定连接点。 比如@args(com.xgj.Monitor)表示任何这样的一个目标方法,它有一个入参且入参对象的类标注@Monitor注解
目标类切点函数
within()
入参:类名匹配串说明:表示特定域下的所有连接点,比如
within(com.xgj.service.*)表示com.xgj.service包中所有的连接点,即包中所有类的所有方法; 而
within(com.xgj.service.*Service)表示在com.xgj.service包中所有以Service结尾的类的所有连接点
target()
入参:类名说明:假如目标类按类型匹配与指定类,则目标类的所有连接点匹配这个切点。 比如通过target(com.xgj.Waiter)定义的切点,Waiter及Waiter实现类NaiveWaiter中的所有连接点都匹配该切点
@within()
入参:类型注解类名说明:假如目标类按类型匹配于某个类A,且类A标注了特定的注解,这目标类的所有连接点匹配这个切点。 比如@within(com.xgj.Monitor)定义的切点,加入Waiter实现了@Monitor注解,这Waiter及Waiter的实现类NaiveWaiter的说哟连接点都匹配这个切点
@target()
入参:类型注解类名说明:假如目标类标注了特定注解,则目标类的所有连接点都匹配该切点。 如@target(com.xgj.Monitor),假设NaiveWaiter标注了@Monitor注解,则NaiveWaiter的所有连接点都匹配这个切点
代理类切点函数
this
入参:类名说明:代理类按类型匹配于指定类,则被代理的目标类的所有连接点都匹配该切点。
注意事项
除了上述的函数外,@AspectJ还有其它的函数 ,比如call()、initialization()等,但是不能够在Spring中使用,否则会抛出IllegalArgumentException异常。在函数入参中使用通配符
有些函数的入参可以接受通配符,@AspectJ支持三种通配符*
*表示匹配任意字符,但它只能匹配上下文中的一个元素
..
..表示匹配任意字符,可以匹配上下文中的 多个元素, 但在标识类时,必须和
*联合使用,而在表示入参时则单独使用
+
+表示按照类型匹配指定类的所有类,必须跟在类名后面,比如com.xgj.Service+。 继承或扩展指定类的所有类,同时还包含指定类本身。
支持通配符的函数说明
支持所有通配符 execution()和within() , 比如within(com.xgj.*)
within(com.xgj.service..*.*Service+)
仅支持“+”通配符: args()、this()和target(). 比如args(com.xgj.Waiter+) 、target(java.util.List+)等。 虽然支持+通配符,但是意义不大。 对于这些函数来讲使用+和不使用+是等价的
不支持通配符: @args()、@within、@target 和 @annotation.
此外,args() this() target() @args() @within() @target() @annotation() 这7个函数除了可以指定类名外,也可以指定变量名,并将目标对象中的变量绑定到增强的方法中。
逻辑运算符
切点表达式由切点函数组成,切点函数之间可以进行逻辑运算,组成复合切点。Spring支持以下切点运算符
&&
与操作符,相当于切点的交集运算。如果在Spring的XML配置文件中使用切点表达式,由于&是XML特殊字符,所以使用转义字符串
&&表示。
为了方便,Spring提供了一个等效的运算符and, 比如
within(com.xgj..*) and args(String)表示在com.xgj包下所有类(当前包以及子孙包)拥有一个String入参的方法;
||
或操作符,相当于切点的并集运算,or是等效的操作符。如within(com.xgj..*) || args(String)表示在com.xgj包下的所有类的方法,或者所有拥有一个String入参的方法;
!
非操作符,相当于切点的反集运算,not是等效的操作符。如!within(com.xgj.*)表示所有不在com.xgj包下的方法。
注意:
在Spring中使用and or 和 not操作符时,允许不在前面添加空格,比如
within(com.xgj..*)andnotargs(String)和
within(com.xgj..*) and not args(String)是等效的,不过为了程序的可读性,我们还是要求在操作符的前后添加空格。
另外,如果not位于切点表达式的开头,则必须在开头添加一个空格,否则会产生解析错误。 比如
not within(com.xgj..*)
不同增强类型
@AspectJ为各种的增强类型提供了不同的注解类,它们位于org.aspectj.lang.annotation.*包中,这些注解类拥有若干个成员,可以通过这些成员完成定义切点信息、绑定连接点参数等操作;此外,这些注解的存留期限都是RetentionPolicy.RUNTIME,标注目标都是ElementType.METHOD。
@Before
前置增强,相当于BeforeAdvice的功能,Before注解类拥有两个成员:
value:该成员用于定义切点;
argNames:由于无法通过Java反射机制获取方法入参名,所有如果在Java编译时未启动调试信息或者需要在运行期解析切点,就必须通过这个成员指定注解所标注增强方法的参数名(注意两者名字必须完全相同),多个参数名用逗号分隔。
@AfterReturning
后置增强,相当于AfterReturningAdvice,AfterReturning注解类拥有4个成员:
value:该成员用于定义切点;
pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
returning:将目标对象方法的返回值绑定给增强的方法;
argNames:如前所述。
@Around
环绕增强,相当于MethodInterceptor,Around注解类拥有两个成员:
value:该成员用于定义切点;
argNames:如前所述。
@Aspect public class AtTargetAspect { @Around("@target(com.xgj.aop.spring.advisor.aspectJ.function.attarget.Mark)") public void crossCuttingCode(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("****AtTargetAspect.crossCuttingCode() : " + joinPoint.getSignature().getName() + ": Before Method Execution"); try { joinPoint.proceed(); } finally { // Do Something useful, If you have } System.out.println("****AtTargetAspect.crossCuttingCode() : " + joinPoint.getSignature().getName() + ": After Method Execution"); } }
@AfterThrowing
抛出增强,相当于ThrowsAdvice.AfterThrowing注解类拥有4个成员:
value:该成员用于定义切点;
pointcut:表示切点的信息,如果显式指定pointcut值,它将覆盖value的设置值,可以将pointcut成员看成是value的同义词;
throwing:将抛出的异常绑定到增强方法中;
argNames:如前所述。
@After
Final增强,不管是抛出异常或者是正常退出,该增强都会得到执行,该增强没有对应的增强接口,可以把它看成是ThrowsAdvice和AfterReturningAdvice的混合物,一般用于释放资源,相当于try{}finally{}的控制流。After注解类拥有两个成员:
value:该成员用于定义切点;
argNames:如前所述。
@DeclareParents
引介增强,相当于IntroductionInterceptor,DeclareParents注解类拥有两个成员:
value:该成员用于定义切点,它表示在哪个目标类上添加引介增强;
defaultImpl:默认的接口实现类。
引介增强用法
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster假设我们希望Waiter能够同时充当Seller的角色,即通过切面技术为NaiveWaiter新增Seller接口的实现。
下面我们使用@AspectJ的引介增强来实现这一个功能。
package com.xgj.aop.spring.advisor.aspectJ.basic; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * * * @ClassName: EnableSellerAspect * * @Description: 希望Waiter也能同时充当Seller的角色 * * @author: Mr.Yang * * @date: 2017年8月26日 上午1:23:41 */ @Aspect public class EnableSellerAspect { // (1)value 为NaiveWaiter添加接口实现, (2)defaultImpl默认的接口实现类 @DeclareParents(value = "com.xgj.aop.spring.advisor.aspectJ.basic.NaiveWaiter", defaultImpl = SmartSeller.class) public Seller seller; // (3) 要实现的目标接口 }
分析:
在EnableSellerAspect 切面中,通过@DeclareParents为NaiveWaiter添加了一个需要实现的Seller接口,并指定其默认实现类为SmartSeller. 然后通过切面技术将SmartSeller融合到NaiveWaiter中,这样NaiveWaiter就实现了Seller接口。
配置文件,配置切面和NaiveWaiter Bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 使用基于Schema的aop命名空间进行配置 --> <!-- 基于@AspectJ切面的驱动器 --> <aop:aspectj-autoproxy/> <!-- 目标Bean --> <bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.basic.NaiveWaiter"/> <!-- 使用了@AspectJ注解的切面类 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.basic.EnableSellerAspect"/> </beans>
测试类:
package com.xgj.aop.spring.advisor.aspectJ.basic; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class EnableSellerAspectTest { @Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:com/xgj/aop/spring/advisor/aspectJ/basic/conf-aspectJ.xml"); Waiter waiter = ctx.getBean("waiter", Waiter.class); waiter.greetTo("XiaoGongJiang"); // 可以成功的进行强制类型转换 Seller seller = (Seller) waiter; seller.sell("beer", "XiaoGongJiang"); } }
运行结果:
2017-08-26 01:42:50,077 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24b9371e: startup date [Sat Aug 26 01:42:50 BOT 2017]; root of context hierarchy 2017-08-26 01:42:50,173 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/basic/conf-aspectJ.xml] NaiveWaiter Greet to XiaoGongJiang SmartSeller: sell beer to XiaoGongJiang
可见,NaiveWaiter已经成功的新增了Seller接口的实现。
相关文章推荐
- 【Spring AOP】AspectJ语法基础
- 实例简述Spring AOP之对AspectJ语法的支持
- »Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- 实例简述Spring AOP之对AspectJ语法的支持
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- 【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- Spring 之AOP AspectJ切入点语法详解(最全面、最详细。)
- [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.
- Spring AOP AspectJ切入点语法详解
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)---zhangkaitao
- Spring AOP AspectJ 语法随记
- Spring AOP AspectJ切入点语法详解,execution,within,this.......
- Spring基础学习(九)——基于AspectJ的两种AOP实现方式
- Spring 之AOP AspectJ切入点语法详解
- »Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- Spring 之AOP AspectJ切入点语法详解(最全了,不需要再去其他地找了)
- AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3
- 整理的Spring AOP AspectJ切入点语法 欢迎补充
- Spring 之AOP AspectJ切入点语法详解