记录生活中的点滴,分享、学习、创新
1、一个简单的例子
Waiter接口:
package com.yyq.annotation; public interface Waiter { void greetTo(String name); void serveTo(String name); }
NaiveWaiter业务类:
package com.yyq.annotation; public class NaiveWaiter implements Waiter { @Override public void greetTo(String name) { System.out.println("NaiveWaiter:greet to " + name + "..."); } @Override public void serveTo(String name) { System.out.println("NaiveWaiter:serving to " + name + "..."); } }
PreGreetingAspect切面实现类:
package com.yyq.annotation; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; //通过该注解将PreGreetingAspect标识为一个切面 @Aspect public class PreGreetingAspect { //定义切点和增强类型 @Before("execution(* greetTo(..))") //增强的横切逻辑 public void beforeGreeting(){ System.out.println("How are you"); } }
测试方法:
@Test public void aspectJProxyTest(){ Waiter target = new NaiveWaiter(); AspectJProxyFactory factory = new AspectJProxyFactory(); //设置目标对象 factory.setTarget(target); //添加切面对象 factory.addAspect(PreGreetingAspect.class); //生成织入切面的代理对象 Waiter proxy = factory.getProxy(); proxy.greetTo("Anny"); proxy.serveTo("Mei"); }
输出结果:
How are you
NaiveWaiter:greet to Anny...
NaiveWaiter:serving to Mei...
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" 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-3.0.xsd"> <!--目标Bean--> <bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/> <!--使用了@AspectJ注解的切面类--> <bean class="com.yyq.annotation.PreGreetingAspect"/> <!--自动代理创建器,自动将@AspectJ注解切面类织入到目标Bean中--> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> </beans>
测试方法:
@Test public void aspectJProxyTest2(){ String configPath = "com\\yyq\\annotation\\beans.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath); Waiter waiter = (Waiter)ctx.getBean("waiter"); waiter.greetTo("John"); }
How are you
NaiveWaiter:greet to John...
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <bean id="waiter" class="com.yyq.annotation.NaiveWaiter"/> <bean class="com.yyq.annotation.PreGreetingAspect"/> </beans>
测试方法:
@Test public void aspectJProxyTest3(){ String configPath = "com\\yyq\\annotation\\beans2.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath); Waiter waiter = (Waiter)ctx.getBean("waiter"); waiter.greetTo("Herry"); }
How are you
NaiveWaiter:greet to Herry...
2、@AspectJ基础 1)切点表达式函数
AspectJ 5的切点表达式由关键字和操作参数组成,如execution(* greetTo(..))的切点表达式,“execute”为关键字,而“* greetTo(..)”为操作参数。在这里,execute代表目标类执行某一方法,而“* greetTo(..)”是描述目标方法的匹配模式串,两者联合起来所表示的切点匹配目标类greetTo()方法的连接点。为了描述方便,我们将 execution()称作函数,而将匹配串“* greetTo(..)”称作函数的入参。
Spring支持9个@ApsectJ切点表达式函数,它们用不同的方式描述目标类的连接点,根据描述对象的不同,可以将它们大致分为4种类型: · 方法切点函数:通过描述目标类方法信息定义连接点; · 方法入参切点函数:通过描述目标类方法入参的信息定义连接点; · 目标类切点函数:通过描述目标类类型信息定义连接点; · 代理类切点函数:通过描述目标类的代理类的信息定义连接点;
类别 | 函数 | 入参 | 说明 |
方法切点函数 | execution() | 方法匹配模式串 | 表示满足某一匹配模式的所有目标类方法连接点。如execution(* greetTo(..))表示所有目标类中的greetTo()方法。 |
@annotation() | 方法注解类名 | 表示标注了特定注解的目标方法连接点。如@annotation(com.baobaotao.anno.NeedTest)表示任何标注了@NeedTest注解的目标类方法。 | |
方法入参切点函数 | args() | 类名 | 通过判别目标类方法运行时入参对象的类型定义指定连接点。如args(com.baobaotao.Waiter)表示所有有且仅有一个按类型匹配于Waiter的入参的方法。 |
@args() | 类型注解类名 | 通过判别目标方法的运行时入参对象的类是否标注特定注解来指定连接点。如@args(com.baobaotao.Monitorable)表示任何这样的一个目标方法:它有一个入参且入参对象的类标注@Monitorable注解。 | |
目标类切点函数 | within() | 类名匹配串 | 表示特定域下的所有连接点。如within(com.baobaotao.service.*)表示 com.baobaotao.service包中的所有连接点,也即包中所有类的所有方法,而 within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,所有以 Service结尾的类的所有连接点。 |
target() | 类名 | 假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点。如通过target(com.baobaotao.Waiter)定义的切点,Waiter、以及Waiter实现类NaiveWaiter中所有连接点都匹配该切点。 | |
@within() | 类型注解类名 | 假如目标类按类型匹配于某个类A,且类A标注了特定注解,则目标类的所有连接点匹配这个切点。如@within(com.baobaotao.Monitorable)定义的切点,假如Waiter类标注了@Monitorable注解,则Waiter以及Waiter实现类NaiveWaiter类的所有连接点都匹配。 | |
@target() | 类型注解类名 | 目标类标注了特定注解,则目标类所有连接点匹配该切点。如@target(com.baobaotao.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter所有连接点匹配切点。 | |
代理类切点函数 | this() | 类名 | 代理类按类型匹配于指定类,则被代理的目标类所有连接点匹配切点。 |
2)在函数入参中使用通配符
@AspectJ支持3种通配符:
@AspectJ函数按其是否支持通配符及支持的程度,可以分为以下3类:
此外,args()、this()、target()、@args()、@within()、@target()和@annotation()这7个函数除了可以指定类名外,也可以指定变量名,并将目标对象中的变量绑定到增强的方法中。
3)逻辑运算符
切点表达式由切点函数组成,切点函数之间还可以进行逻辑运算,组成复合切点,Spring支持以下的切点运算符:
4)不同增强类型
@AspectJ为各种的增强类型提供了不同的注解类,它们位于org.aspectj.lang.annotation.*包中,这些注解类拥有若干个成员,可以通过这些成员完成定义切点信息、绑定连接点参数等操作;此外,这些注解的存留期限都是RetentionPolicy.RUNTIME,标注目标都是ElementType.METHOD。
前置增强,相当于BeforeAdvice的功能,Before注解类拥有两个成员:
后置增强,相当于AfterReturningAdvice,AfterReturning注解类拥有4个成员:
环绕增强,相当于MethodInterceptor