目录
格式:@ 注解(value=“表达标签 ( 表达式格式)”)
如:@Pointcut (value=“execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(…))”)
其中execution 是用的最多的,
execution(
modifier-pattern?
ret-type-pattern
declaring-type-pattern?
name-pattern(param-pattern)
throws-pattern?
)
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
其中带 ?号的 modifiers-pattern?,declaring-type-pattern?,hrows-pattern?是可选项
ret-type-pattern,name-pattern, parameters-pattern是必选项;
(..)代表所有参数,
()代表一个参数,
(,String)代表第一个参数为任何值,第二个为String类型.
说明:最靠近(..)的为方法名,靠近.∗(..))的为类名或者接口名,如上例的JoinPointObjP2.∗(..))
如:
当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型.
@within和@target针对类的注解,@annotation是针对方法的注解
Pointcut定义时,还可以使用&&、∣∣、!运算符
- @Pointcut("execution(* com.savage.aop.MessageSender.*(..)) && args(param)")
- public void log(){
- }
-
- @Before("log(String param)")
- public void beforeLog(){
- //todo something....
- }
-
- //等同于
- @Before("execution(* com.savage.aop.MessageSender.*(..)) && args(param)")
- public void beforeLog(){
- //todo something....
- }
又如:
- @Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
- private void logSender(){}
-
- @Pointcut("execution(* com.savage.aop.MessageReceiver.*(..))")
- private void logReceiver(){}
-
- @Pointcut("logSender() || logReceiver()")
- private void logMessage(){}
这个例子中,logMessage()将匹配任何MessageSender和MessageReceiver中的任何方法
示例 | 描述 | |
public * *(..) | 任何公共方法的执行 | |
* cn.javass..IPointcutService.*() | cn.javass包及所有子包下IPointcutService接口中的任何无参方法 | |
* cn.javass..*.*(..) | cn.javass包及所有子包下任何类的任何方法 | |
* cn.javass..IPointcutService.*(*) | cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法 | |
* (!cn.javass..IPointcutService+) .*(..) | 非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法 | |
* cn.javass..IPointcutService+.*() | cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法 | |
* cn.javass..IPointcut*.test*(java.util.Date) | cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的,如定义方法:public void test(Object obj);即使执行时传入java.util.Date,也不会匹配的; | |
* cn.javass..IPointcut*.test*(..) throws IllegalArgumentException, ArrayIndexOutOfBoundsException,cn.javass | 包及所有子包下IPointcut前缀类型的的任何方法,且抛出IllegalArgumentException和ArrayIndexOutOfBoundsException异常 | |
* (cn.javass..IPointcutService+&& java.io.Serializable+).*(..) | 任何实现了cn.javass包及所有子包下IPointcutService接口和java.io.Serializable接口的类型的任何方法 | |
@java.lang.Deprecated * *(..) | 任何持有@java.lang.Deprecated注解的方法 | |
@java.lang.Deprecated @cn.javass..Secure* *(..) | 任何持有@java.lang.Deprecated和@cn.javass…Secure注解的方法 | |
@(java.lang.Deprecated | cn.javass..Secure) **(..) | |
(@cn.javass..Secure*) *(..) | 任何返回值类型持有@cn.javass…Secure的方法 | |
*(@cn.javass..Secure*).*(..) | 任何定义方法的类型持有@cn.javass…Secure的方法 | |
**(@cn.javass..Secure(*) ,@cn.javass..Secure(*)) | 任何签名带有两个参数的方法,且这个两个参数都被@ Secure标记了,如public void test(@Secure String str1, @Secure String str1); | |
**((@ cn.javass..Secure *))或**(@ cn.javass..Secure*) |
| |
如public void test(Model model);且Model类上持有@Secure注解 | ||
* *(@cn.javass…Secure (@cn.javass…Secure *) ,@ cn.javass…Secure (@cn.javass…Secure *)) | 任何带有两个参数的方法,且这两个参数都被@ cn.javass…Secure标记了;且这两个参数的类型上都持有@ cn.javass…Secure; | |
* *(java.util.Map | 任何带有一个java.util.Map参数的方法,且该参数类型是以< cn.javass…Model, cn.javass…Model >为泛型参数;注意只匹配第一个参数为java.util.Map,不包括子类型;如public void test(HashMap | |
* *(java.util.Collection<@cn.javass…Secure *>) | 任何带有一个参数(类型为java.util.Collection)的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有@cn.javass…Secure注解;如public void test(Collection collection);Model类型上持有@cn.javass…Secure | |
* *(java.util.Set extends HashMap>) | 任何带有一个参数的方法,且传入的参数类型是有一个泛型参数,该泛型参数类型继承与HashMap;Spring AOP目前测试不能正常工作 | |
* *(java.util.List super HashMap>) | 任何带有一个参数的方法,且传入的参数类型是有一个泛型参数,该泛型参数类型是HashMap的基类型;如public voi test(Map map);Spring AOP目前测试不能正常工作 | |
* (<@cn.javass…Secure *>) | 任何带有一个参数的方法,且该参数类型是有一个泛型参数,该泛型参数类型上持有@cn.javass…Secure注解;Spring AOP目前测试不能正常工作 |
示例 | 描述 |
within(cn.javass..*) | cn.javass包及子包下的任何方法执行 |
within(cn.javass..IPointcutService+) | cn.javass包或所有子包下IPointcutService类型及子类型的任何方法 |
within(@cn.javass..Secure *) | 持有cn.javass…Secure注解的任何类型的任何方法必须是在目标对象上声明这个注解,在接口上声明的对它不起作用 |
示例 | 描述 |
this(cn.javass.spring.chapter6.service. IPointcutService) | 当前AOP对象实现了 IPointcutService接口的任何方法 |
this(cn.javass.spring.chapter6.service. IIntroductionService) | 当前AOP对象实现了 IIntroductionService接口的任何方法 |
示例 | 描述 |
target(cn.javass.spring.chapter6. service.IPointcutService) | 当前目标对象(非AOP对象)实现了 IPointcutService接口的任何方法 |
target(cn.javass.spring. chapter6.service.IIntroductionService) | 当前目标对象(非AOP对象) 实现了IIntroductionService 接口的任何方法, 不可能是引入接口 |
示例 | 描述 |
args (java.io.Serializable,…) | 任何一个以接受“传入参数类型为 java.io.Serializable” 开头,且其后可跟任意个任意类型的参数的方法执行,args指定的参数类型是在运行时动态匹配的 |
示例 | 描述 |
@within(cn.javass.spring.chapter6.Secure) | 任何目标对象对应的类型持有Secure注解的类方法; |
示例 | 描述 |
@target (cn.javass.spring.chapter6.Secure) | 任何目标对象持有Secure注解的类方法;必须是在目标对象上声明这个注解,在接口上声明的对它不起作用 |
示例 | 描述 |
@args (cn.javass.spring.chapter6.Secure) | 任何一个只接受一个参数的方法,且方法运行时传入的参数持有注解 cn.javass.spring.chapter6.Secure;动态切入点,类似于arg指示符; |
示例 | 描述 |
@annotation(cn.javass.spring. chapter6.Secure ) | 当前执行方法上持有注解 cn.javass.spring.chapter6.Secure将被匹配 |
示例 | 描述 |
bean(*Service) | 匹配所有以Service命名(id或name)结尾的Bean |
- @Pointcut(value="bean(*Service)")
- private void pointcut1(){
- }
-
- @Pointcut(value="@args()cn.javass.spring.chaper6.Source")
- public referencePointcutTest(JoinPoint jp){
- ...
- }
使用如下方式在通知方法上声明,必须是在第一个参数,然后使用jp.getArgs()就能获取到被通知方法参数
- @Before(value="execution(* sayBefore(*))")
- public void before(JoinPoint jp) {}
-
- @Before(value="execution(* sayBefore(*))")
- public void before(JoinPoint.StaticPart jp) {}
自动获取:通过切入点表达式可以将相应的参数自动传递给通知方法,例如前边章节讲过的返回值和异常是如何传递给通知方法的。
在Spring AOP中,除了execution和bean指示符不能传递参数给通知方法,其他指示符都可以将匹配的相应参数或对象自动传递给通知方法。
- @Before(value="execution(* test(*)) && args(param)", argNames="param")
- public void before1(String param) {
- System.out.println("===param:" + param);
- }
切入点表达式execution(* test()) && args(param) :
1)首先execution( test(*))匹配任何方法名为test,且有一个任何类型的参数;
2)args(param)将首先查找通知方法上同名的参数,并在方法执行时(运行时)匹配传入的参数是使用该同名参数类型,即java.lang.String;如果匹配将把该被通知参数传递给通知方法上同名参数。
其他指示符(除了execution和bean指示符)都可以使用这种方式进行参数绑定。
在此有一个问题,即前边提到的类似于【3.1.2构造器注入】中的参数名注入限制:在class文件中没生成变量调试信息是获取不到方法参数名字的。
所以我们可以使用策略来确定参数名:
如果我们通过“argNames”属性指定了参数名,那么就是要我们指定的;
- @Before(value=" args(param)", argNames="param") //明确指定了
- public void before1(String param) {
- System.out.println("===param:" + param);
- }
如果第一个参数类型是JoinPoint、ProceedingJoinPoint或JoinPoint.StaticPart类型,应该从“argNames”属性省略掉该参数名(可选,写上也对),这些类型对象会自动传入的,但必须作为第一个参数;
- @Before(value=" args(param)", argNames="param") //明确指定了
- public void before1(JoinPoint jp, String param) {
- System.out.println("===param:" + param);
- }
如果“class文件中含有变量调试信息”将使用这些方法签名中的参数名来确定参数名;
- @Before(value=" args(param)") //不需要argNames了
- public void before1(JoinPoint jp, String param) {
- System.out.println("===param:" + param);
- }
如果没有“class文件中含有变量调试信息”,将尝试自己的参数匹配算法,如果发现参数绑定有二义性将抛出AmbiguousBindingException异常;对于只有一个绑定变量的切入点表达式,而通知方法只接受一个参数,说明绑定参数是明确的,从而能配对成功。
- @Before(value=" args(param)")
- public void before1(JoinPoint jp, String param) {
- System.out.println("===param:" + param);
- }
以上策略失败将抛出IllegalArgumentException。
接下来让我们示例一下组合情况吧:
- @Before(args(param) && target(bean) && @annotation(secure)",
- argNames="jp,param,bean,secure")
- public void before5(JoinPoint jp, String param,
- IPointcutService pointcutService, Secure secure) {
- ……
- }
也可以对使用命名切入点自动获取参数:
- @Pointcut(value="args(param)", argNames="param")
- private void pointcut1(String param){}
- @Pointcut(value="@annotation(secure)", argNames="secure")
- private void pointcut2(Secure secure){}
-
- @Before(value = "pointcut1(param) && pointcut2(secure)", argNames="param, secure")
- public void before6(JoinPoint jp, String param, Secure secure) {
- ……
- }
- @Aspect
- @Component
- public class NotVeryUsefulAspect {
- @AfterReturning(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
- private void logReceiver(){
- System.out.println("切入点logReceiver...");
- }
-
- @Pointcut(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..)) && args(param)")
- private void pointcut(String param){
- System.out.println("切入点pointcut()"+param);
- }
-
- //方法体将不执行
- @Pointcut("within(com.cn.spring.aspectj.*)")
- public String inWebLayer() {
- System.out.println("切入点inWebLayer()");
- return "返回值加载";
- }
-
- @Before(value="inWebLayer()")
- private void beforeinWebLayer(){
- System.out.println("beforeinWebLayer~~");
- }
-
- @Before(value="pointcut(param)")
- private void beforePointcut(String param){
- System.out.println("beforePointcut:"+param);
- }
-
-
- @AfterReturning(pointcut="inWebLayer()",returning="retVal")
- public void doAccessCheck(Object retVal) {
- System.out.println("doAccessCheck:"+retVal);
- }
-
- @Around(value="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(..))")
- private Object aroundLayer(ProceedingJoinPoint pjp) throws Throwable{
- // start stopwatch
- Object retVal = pjp.proceed();
- // stop stopwatch
- System.out.println("aroundLayer~~");
- return retVal;
- }
- }