AOP中注解参数详解_第1页
AOP中注解参数详解_第2页
AOP中注解参数详解_第3页
AOP中注解参数详解_第4页
AOP中注解参数详解_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、aop编程中注解参数详解pointcut(execution(* transfer(.)private void anyoldtransfer() 切入点指定者的支持spring aop 支持在切入点表达式中使用如下的 aspectj 切入点指定者:1: execution :匹配方法执行的连接点,这是你将会用到的 spring 的最主要的切入点指定者。2: within :限定匹配特定类型的连接点(在使用 spring aop的时候,在匹配的类型中定义的方法的执行)。3: this :限定匹配特定的连接点 (使用spring aop勺时候方法的执行),其中bean reference( sp

2、ring aop 代理)是指定类型的实例。4: target :限定匹配特定的连接点(使用 spring aop 的时候方法的执行),其中目标对象(被代理的 appolication object )是指定类型的实例。5: args :限定匹配特定的连接点(使用 spring aop 的时候方法的执行),其中参数是指定类型的实例。6: target :限定匹配特定的连接点(使用 spring aop的时候方法的执行),其中执行的对象的类已经有指定类型的注解。7: args:限定匹配特定的连接点(使用 spring aop的时候方法的执行),其中实际传入参数的运行时类型有指定类型的注解。8: w

3、ithin : 限定匹配特定的连接点, 其中连接点所在类型已指定注解 (在使用 spring aop 的时候,所执行的方法所在类型已指定注解)。9: annotation :限定匹配特定的连接点(使用 spring aopw时候方法的执行),其中连接点的主题有某种给定的注解合并切入点表达式切入点表达式可以使用 &, | 和 ! 来合并 . 还可以通过名字来指向切入点表达式。切入点表达式的基本语法spring aop 用户可能会经常使用 execution pointcut designator 。执行表达式的格式如下:execution(modifiers-pattern? ret-type-

4、pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)除了返回类型模式(上面代码片断中的 ret-type-pattern ),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。类型匹配模式1: * : 匹配任何数量字符; 比如模式 (*,string) 匹配了一个接受两个参数的方法, 第一个可以是任意类型,第二个则必须是string 类型2: . :匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数,可以

5、使零到多个。3: + :匹配指定类型的子类型;仅能作为后缀放在类型模式后边。类型匹配模式示例1: java.lang.string 匹配 string 类型;2: java.*.string 匹配 java 包下的任何“一级子包”下的 string 类型;如匹配 java.lang.string ,但不匹配java.lang.ss.string3: java.*匹配 java 包及任何子包下的任何类型;如匹配 java.lang.string 、 java.lang.annotation.annotation4: java.lang.*ing 匹配任何 java.lang 包下的以 ing 结

6、尾的类型;5: java.lang.number+ 匹配 java.lang 包下的任何 number 的子类型;如匹配 java.lang.integer ,也匹配 java.math.biginteger切入点表达式的基本示例,使用 execution1: public * *(.)任何公共方法的执行2: * cn.javass.ipointcutservice.*()cn.javass 包及所有子包下ipointcutservice 接口中的任何无参方法3: * cn.javass.*.*(.)cn.javass 包及所有子包下任何类的任何方法4: * cn.javass.ipointc

7、utservice.*(*)cn.javass 包及所有子包下ipointcutservice 接口的任何只有一个参数方法5: * (!cn.javass.ipointcutservice+).*(.)非“ cn.javass 包及所有子包下ipointcutservice 接口及子类型”的任何方法6: * cn.javass.ipointcutservice+.*()cn.javass 包及所有子包下ipointcutservice 接口及子类型的的任何无参方法7: * cn.javass.ipointcut*.test*(java.util.date)cn.javass 包及所有子包下ip

8、ointcut 前缀类型的的以 test 开头的只有一个参数类型为java.util.date 的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的如定义方法: public void test(object obj); 即使执行时传入 java.util.date ,也不会匹配的。8: * cn.javass.ipointcut*.test*(.) throws illegalargumentexception,arrayindexoutofboundsexceptioncn.javass 包及所有子包下ipointcut 前缀类型的的任何方法,且抛出i

9、llegalargumentexception和 arrayindexoutofboundsexception异常9: * (cn.javass.ipointcutservice+ & java.io.serializable+).*(.)任何实现了 cn.javass 包及所有子包下ipointcutservice 接口和 java.io.serializable接口的类型的任何方法10: java.lang.deprecated * *(.)任何持有java.lang.deprecated注解的方法11: java.lang.deprecated cn.javass.secure * *(

10、.)任何持有java.lang.deprecated和 cn.javass.secure注解的方法12: (java.lang.deprecated | cn.javass.secure) * *(.)任何持有java.lang.deprecated或 cn.javass.secure注解的方法13: (cn.javass.secure *) *(.)任何返回值类型持有cn.javass.secure 的方法14: * (cn.javass.secure *).*(.)任何定义方法的类型持有cn.javass.secure 的方法15: * *(cn.javass.secure (*) , c

11、n.javass.secure (*)任何签名带有两个参数的方法,且这个两个参数都被 secure 标记了,如 public voidtest(secure string str1, secure string str1); 16: * *( cn.javass.secure *) 或* *( cn.javass.secure *)任何带有一个参数的方法,且该参数类型持有 cn.javass.secure;如 public voidtest(model model); 且 model 类上持有 secure注解17: * *(cn.javass.secure (cn.javass.secure

12、 *) , cn.javass.secure(cn.javass.secure *)任何带有两个参数的方法,且这两个参数都被cn.javass.secure 标记了;且这两个参数的类型上都持有 cn.javass.secure ;18: * *(java.util.map, .)任何带有一个java.util.map 参数的方法,且该参数类型是以为泛型参数;注意只匹配第一个参数为 java.util.map, 不包括子类型;如 public void test(hashmap map, string str);将不匹配,必须使用“*(java.util.hashmap,.) ”进行匹配;而 p

13、ublicvoid test(map map, int i); 也将不匹配,因为泛型参数不匹配19: * *(java.util.collection)任何带有一个参数(类型为 java.util.collection )的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有cn.javass.secure注解;如 public voidtest(collection collection);model类型上持有cn.javass.secure切入点表达式的基本示例,使用 within 匹配指定类型内的方法1: within(cn.javass.*)cn.javass 包及子包下的任何方法

14、执行2: within(cn.javass.ipointcutservice+)cn.javass 包或所有子包下ipointcutservice 类型及子类型的任何方法3: within(cn.javass.secure *)持有cn.javass.secure注解的任何类型的任何方法必须是在目标对象上声明这个注解, 在接口上声明的对它不起作用切入点表达式的基本示例,使用 this使用“this(类型全限定名)”匹配当前aop弋理对象类型的执行方法;注意是aop代理对象的类型匹配,这样就可能包括引入接口方法也可以匹配;注意this 中使用的表达式必须是类型全限定名,不支持通配符1: this

15、(cn.javass.spring.chapter6.service.ipointcutservice)当前aop对象实现了 ipointcutservice接口的任何方法2: this(cn.javass.spring.chapter6.service.iintroductionservice)当前aop对象实现了 ilntroductionservice接口的任何方法也可能是引入接口切入点表达式的基本示例,使用 target使用 “ target( 类型全限定名 ) ” 匹配当前目标对象类型的执行方法; 注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;注意target 中使用的表

16、达式必须是类型全限定名,不支持通配符1: target(cn.javass.spring.chapter6.service.ipointcutservice)当前目标对象(非aop寸象)实现了 ipointcutservice 接口的任何方法2: target(cn.javass.spring.chapter6.service.iintroductionservice)当前目标对象(非aop寸象)实现了 ilntroductionservice 接口的任何方法不可能是引入接口切入点表达式的基本示例,使用 args使用 “ args( 参数类型列表) ” 匹配当前执行的方法传入的参数为指定类型的

17、执行方法; 注意是匹配传入的参数类型, 不是匹配方法签名的参数类型; 参数类型列表中的参数必须是类型全限定名,通配符不支持; args 属于动态切入点,这种切入点开销非常大,非特殊情况最好不要使用1: args (java.io.serializable,.)任何一个以接受 “传入参数类型为 java.io.serializable ” 开头, 且其后可跟任意个任意类型的参数的方法执行, args 指定的参数类型是在运行时动态匹配的切入点表达式的基本示例,使用 within使用“ within( 注解类型 ) ”匹配所以持有指定注解类型内的方法;注解类型也必须是全限定类型名1: within

18、cn.javass.spring.chapter6.secure)任何目标对象对应的类型持有secure 注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用切入点表达式的基本示例,使用 target使用“ target( 注解类型 ) ”匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;注解类型也必须是全限定类型名1: target (cn.javass.spring.chapter6.secure)任何目标对象持有secure 注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用切入点表达式的基本示例,使用 args使用“args(注解列表

19、)”匹配当前执行的方法传入的参数持有指定注解的执行;注解类型也必须是全限定类型名1: args (cn.javass.spring.chapter6.secure)任何一个只接受一个参数的方法,且方法运行时传入的参数持有注解cn.javass.spring.chapter6.secure ;动态切入点,类似于arg 指示符;切入点表达式的基本示例,使用annotation使用“ annotation( 注解类型 ) ”匹配当前执行方法持有指定注解的方法;注解类型也必须是全限定类型名1: annotation(cn.javass.spring.chapter6.secure )当前执行方法上持有

20、注解cn.javass.spring.chapter6.secure 将被匹配切入点表达式的基本示例,使用 bean使用“bean(bean id 或名字通配符)”匹配特定名称的bean对象的执彳t方法;spring aop扩展的,在aspectj 中无相应概念1: bean(*service)匹配所有以 service 命名(id或name)结尾的bean切入点表达式的基本示例,使用 reference pointcut引用其他命名切入点,只有apectj风格支持,schema风格不支持,如下所示:java 代码:查看复制到剪贴板打印pointcut(value=bean(*service)

21、 / 命名切入点1private void pointcut1()命名切入点2pointcut(value=args(cn.javass.spring.chapter6.secure) /private void pointcut2()before(value = pointcut1() & pointcut2() / 引用命名切入点public void referencepointcuttest1(joinpoint jp) dump(pointcut1() & pointcut2(), jp);声明通知通知是跟一个切入点表达式关联起来的, 并且在切入点匹配的方法执行之前或者之后或者之前和

22、之后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式。前置通知( before advice ) ,使用 before 注解声明java 代码:查看复制到剪贴板打印aspectpublic class beforeexample before(execution(* com.xyz.myapp.dao.*.*(.)public void doaccesscheck() / .返回后通知( after returning advice ) ,使用 afterreturning 注解声明后通知( after (finally) advice ) ,使用 af

23、ter 注解声明抛出后通知( after throwing advice ) ,使用 afterthrowing 注解声明可以将抛出的异常绑定到通知的一个参数上 ,如下:java 代码:查看复制到剪贴板打印afterthrowing(pointcut=com.xyz.myapp.systemarchitecture.dataaccessoperation(),throwing=ex)public void dorecoveryactions(exception ex) / .环绕通知( around advice ) ,使用 around 注解声明java 代码:查看复制到剪贴板打印aroun

24、d(com.xyz.myapp.systemarchitecture.businessservice()public object dobasicprofiling(proceedingjoinpoint pjp) throws throwable / start stopwatchobject retval = ceed();/ stop stopwatchreturn retval;给 advice 传递参数通常情况下, advice 都需要获取一定的参数, 比如: before 需要截获传入的参数, 而 after需要获取方法的返回值等等。下面介绍两种方式方式一:使用 jo

25、inpoint 来给 advice 的方法传递参数spring ao次供使用org.aspectj.lang.joinpoint类型获取连接点数据,任何通知方法的第一个参数都可以是joinpoint( 环绕通知是proceedingjoinpoint , joinpoint 子类 ) ,当然第一个参数位置也可以是joinpoint.staticpart 类型,这个只返回连接点的静态部分。1: joinpoint :提供访问当前被通知方法的目标对象、代理对象、方法参数等数据java 代码:查看复制到剪贴板打印public interface joinpoint string tostring()

26、; / 连接点所在位置的相关信息string toshortstring(); / 连接点所在位置的简短相关信息string tolongstring(); / 连接点所在位置的全部相关信息object getthis(); 返回aop弋理对象object gettarget(); /返回目标对象object getargs(); /返回被通知方法参数列表signature getsignature(); / 返回当前连接点签名sourcelocation getsourcelocation();/ 返回连接点方法所在类文件中的位置string getkind(); / 连接点类型static

27、part getstaticpart(); /返回连接点静态部分2: proceedingjoinpoint :用于环绕通知,使用 proceed() 方法来执行目标方法java 代码:查看复制到剪贴板打印public interface proceedingjoinpoint extends joinpoint public object proceed() throws throwable;public object proceed(object args) throws throwable;3: joinpoint.staticpart :提供访问连接点的静态部分,如被通知方法签名、连接

28、点类型等java 代码:查看复制到剪贴板打印public interface staticpart signature getsignature(); / 返回当前连接点签名string getkind(); / 连接点类型 int getid(); / 唯一标识string tostring(); / 连接点所在位置的相关信息string toshortstring(); / 连接点所在位置的简短相关信息string tolongstring(); / 连接点所在位置的全部相关信息 4:示例:使用如下方式在通知方法上声明,必须是在第一个参数,然后使用jp.getargs()就能获取到被通知方

29、法参数:java 代码:查看复制到剪贴板打印before(value=execution(* saybefore(*)public void before(joinpoint jp) before(value=execution(* saybefore(*)public void before(joinpoint.staticpart jp) 方式二:使用 args 来给 advice 的方法传递参数,示例如:java 代码:查看复制到剪贴板打印before(value=execution(* test(*) & args(param), argnames=param)public void

30、before1(string param) system.out.println(=param: + param);切入点表达式execution(* test(*) & args(param):( 1 )首先 execution(* test(*) 匹配任何方法名为 test ,且有一个任何类型的参数;( 2 ) args(param) 将首先查找通知方法上同名的参数,并在方法执行时 (运行时) 匹配传入的参数是使用该同名参数类型,即 java.lang.string ;如果匹配将把该被通知参数传递给通知方法上同名参数。参数匹配的策略1:可以通过argnames”属性指定参数名,示例如:ja

31、va 代码:查看复制到剪贴板打印before(value= args(param), argnames=param) / 明确指定了public void before1(string param) system.out.println(=param: + param);2:如果第一个参数类型是joinpoint 、 proceedingjoinpoint 或 joinpoint.staticpart 类型,应该从“ argnames”属性省略掉该参数名(可选,写上也对),这些类型对象会自动传入的,但必须作为第一个参数 。示例如:java 代码:查看复制到剪贴板打印before(value=

32、args(param), argnames=param) / 明确指定了public void before1(joinpoint jp, string param) system.out.println(=param: + param);3:如果“class 文件中含有变量调试信息”, spring 将可以使用这些方法签名中的参数名来确定参数名,示例如下:java 代码:查看复制到剪贴板打印before(value= args(param) / 不需要 argnames 了public void before1(joinpoint jp, string param) system.out.p

33、rintln(=param: + param);4:如果没有“class 文件中含有变量调试信息”,将尝试自己的参数匹配算法,如果发现参数绑定有二义性将抛出 ambiguousbindingexception 异常; 对于只有一个绑定变量的切入点表达式,而通知方法只接受一个参数,说明绑定参数是明确的,从而能配对成功 ,示例如下:before(value= args(param)public void before1(joinpoint jp, string param) system.out.println(=param: + param);5:以上策略失败将抛出illegalargument

34、exception 。处理参数java 代码:查看复制到剪贴板打印around(execution(list find*(.) & +com.xyz.systemarchitecture.indataaccesslayer() & +args(accountholdernamepattern)public object preprocessquerypattern(proceedingjoinpoint pjp, stringaccountholdernamepattern)throws throwable string newpattern = preprocess(accountholde

35、rnamepattern);return ceed(new object newpattern);获取方法运行后的返回值java 代码:查看复制到剪贴板打印afterreturning(pointcut=com.xyz.myapp.systemarchitecture.dataaccessoperation(),returning=retval)public void doaccesscheck(object retval) / .advice 执行的顺序如果有多个通知想要在同一连接点运行会发生什么? spring aop 的执行通知的顺序跟aspectj 的一样。 在“进入”连

36、接点的情况下,最高优先级的通知会先执行(所以上面给出的两个前置通知( before advice )中,优先级高的那个会先执行)。 在“退出”连接点的情况下, 最高优先级的通知会最后执行。 只需要记住通知是按照定义的顺序来执行的就可以了。当定义在 不同的 切面里的两个通知都需要在一个相同的连接点中运行,那么除非你指定,否则执行的顺序是未知的。 你可以通过指定优先级来控制执行顺序。 在 spring 中可以在切面类中实现org.springframework.core.ordered 接口做到这一点。 在两个切面中,ordered.getvalue() 方法返回值较低的那个有更高的优先级。jav

37、a 代码:查看复制到剪贴板打印声明一个切面: .声明一个切入点 : 在切面里面声明一个切入点和声明一个顶级的切入点非常类似:java 代码:查看复制到剪贴板打印.当需要连接子表达式的时候,&在xml中用起来非常不方便,所以关键字and, or 和not 可以分别用来代替&, | 和 !。java 代码:查看复制到剪贴板打印声明通知 advice , before advice.返回后通知( after returning advice ).java 代码:查看复制到剪贴板打印抛出异常后通知( after throwing advice ).后通知( after (finally) advice

38、 ).around 通知java 代码:查看复制到剪贴板打印.通知的参数,可以通过arg-names 属性来实现java 代码:查看复制到剪贴板打印advisoradvisors 这个概念来自 spring1.2 对aop的支持,在 aspectj中是没有等价的概念。 advisor 就像一个小的自包含的切面,这个切面只有一个通知。java 代码: 查看复制到剪贴板打印 spring aop 还是完全用 aspectj ? 优先选用spring的aop因为它不是一个人在战斗,spring除了 aop还有ioc,还有事务等其他功能。 如果你需要通知 domain 对象或其它没有在 spring

39、容器中 管理的任意对象,那么你需要使 用 aspectj 。 spring aop 中使用 aspectj 还是xml?优先使用 aspectj。xmlm格有两个缺点。第一是它不能完全将需求实现的地方封装到一个位置。drym则中说系统中的每一项知识都必须具有单一、无歧义、权威的表示。当使用xml风格时,如何实现一个需求的知识被分割到支撑类的声明中以及xml配置文件中。当使用aspectj风格时就只有一个单独的模块-切面-信息被封装了起来。第二是xml风格同aspectj风格所能表达的内容相比有更多的限制:仅仅支持singleton切面实例模型,并且不能在xml中组合命名连接点的声明。sprin

40、g aop使用jdk动态代理或者 cglib来为目标对象创建代理。如果被代理的目标对象 实现了至少一个接口,则会使用jdk动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个 cglib代理。 如果你希望强制使用 cglib代理,(例如:希望代理目标对象的所有方法,而不只是实现自 接口的方法)那也可以。但是需要考虑以下问题 : 1:无法通知( advise ) final 方法,因为他们不能被覆写。2:将cglib 2二进制发行包放在 classpath下面,jdk本身就提供了动态代理3:强制使用cglib代理需要将 的proxy-target-class 属

41、性设为true:4:当需要使用 cglib代理和aspectj自动代理支持,请按照如下的方式设置 的 proxy-target-class 属性:切入点的 apiorg.springframework.aop.pointcut 是最核心的接口,用来将通知应用于特定的类和方法,完整的接口定义如下:java 代码:查看复制到剪贴板打印public interface pointcut classfilter getclassfilter();methodmatcher getmethodmatcher();1: 将 pointcut 接口分割成有利于重用类和方法匹配的两部分, 以及进行更细粒度的操

42、作组合(例如与另一个方法匹配实现进行“或操作”)。2: classfilter 接口用来将切入点限定在一个给定的类集合中。 如果 matches() 方法总是返回 true ,所有目标类都将被匹配:public interface classfilter boolean matches(class clazz);3: methodmatcher 接口通常更重要,完整的接口定义如下:java 代码:查看复制到剪贴板打印public interface methodmatcher boolean matches(method m, class targetclass);boolean isrunt

43、ime();boolean matches(method m, class targetclass, object args);matches(method, class) 方法用来测试这个切入点是否匹配目标类的指定方法。这将在aop代理被创建的时候执行, 这样可以避免在每次方法调用的时候都执行。 如果 matches(method,class ) 对于一个给定的方法返回 true ,并且 isruntime() 也返回 true ,那么 matches(method, class , object) 将在每个方法调用的时候被调用。这使得切入点在通 知将被执行前可以查看传入到方法的参数。大多数

44、 methodmatcher 是静态的,这意味着isruntime() 方法返回 false 。在这种情况下,matches(method, class , object) 永远不会被调用。静态切入点静态切入点基于方法和目标类进行切入点判断而不考虑方法的参数。 在多数情况下, 静态切 入点是高效的、最好的选择。 spring 只在第一次调用方法时执行静态切入点:以后每次调用这个方法时就不需要再执行。1:正则表达式切入点正则表达式是最常用的描述静态切入点的方式,多数aopi1架都支持这种方式。org.springframework.aop.support.perl5regexpmethodpoi

45、ntcut是一个最基本的正则表达式切入点, 它使用 perl 5 正则表达式语法。示例如下:java 代码:查看复制到剪贴板打印.*set.*.*absquatulate拦截 around 通知spring里使用方法拦截的 around通知兼容aop盟接口。实现 around通知的 methodinterceptor 应当实现下面的接口:java 代码:查看复制到剪贴板打印public interface methodinterceptor extends interceptor object invoke(methodinvocation invocation) throws throwab

46、le;提示:在 invok 方法里面不要忘记调用: ceed();前置通知java 代码:查看复制到剪贴板打印public interface methodbeforeadvice extends beforeadvice void before(method m, object args, object target) throws throwable;后置通知java 代码:查看复制到剪贴板打印public interface afterreturningadvice extends advice void afterreturning(object returnvalue, method m, object args, object target)throws throwable;异常通知如果连接点抛出异常,异常通知( throws advice )将在连接点返回后被调用。 spring 提供类型检查的异常通知,这意味着org.springframework.aop.throwsadvice 接口不包含任何方法:它只是一个标记接口用来标识 所给对象实现了一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论