Spring_9_AspectJ-Advice定义及实例

=Advice定义及实例===================================================
Before advice


import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MoocAspect {
 
 @Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")//在执行com.imooc.aop.aspectj包下以Biz结尾的类所有方法时匹配Advice
 public void before() {
  System.out.println("Before.");
 } 
}

=============================================
After Returning advice

@Aspect
public class AfterReturningExample {
 @AfterReturning("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
 public void doAccessCheck() {
 //...
 }
}
·有时又需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定返回值的形式
@Aspect
public class AfterReturningExample {
 @AfterReturning(
     pointcut="com.xyz.myapp.SystemArchitecture.dateAccessOperation()",
     returning="retVal")
 public void doAccessCheck(Object retVal) //不确定返回值类型,使用Object,确定时可使用相应类型
 {
 //...
 }
}
====================================================
After Throwing advice

@Aspect
public class AfterThrowingExample {
 @AfterThrowing("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
 public void doAccessCheck() {
 //...
 }
}
·有时又需要在通知体内得到返回的实际值,可以使用@AfterThrowing绑定返回值的形式
@Aspect
public class AfterThrowingExample {
 @AfterThrowing(
     pointcut="com.xyz.myapp.SystemArchitecture.dateAccessOperation()",
     throwing="ex")
 public void doAccessCheck(DateAccessException ex) //不确定返回值类型,使用Object,确定时可使用相应类型
 {
 //...
 }
}
====================================================
After (finally) advice
最终通知必须准备处理正常和异常两种返回情况,它通常用于释放资源
像是java的try catch finally代码块的finally 通常用于释放资源
@Aspect
public class AfterFinallyExample {
 @After("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
 public void doReleaseLock() {
 //...
 }
}
====================================================
Around advice
·环绕通知使用@Around注解来生命,通知方法的第一个参数必ProceedingJoinPoint类型
·在通知内部调用ProceedingJoinPoint的proceed()方法导致执行真正的方法,传到一个Object[]对象,
数组中的值将作为参数传递给方法 proceed[proʊˈsi:d]vi.进行;前进;尤指打断后)继续说 n收入获利
@Aspect
public class AroundExample {
 @Around("com.xyz.myapp.SystemArchitecture.dateAccessOperation()")
 public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Trowable {//pjp.proceed()可能会抛出异常处理方式1.throws 该exception2.catch该异常
 //start stopwatch
 Object retVal = pjp.proceed();//真正执行方法的步骤,不知道真正的方法是否有返回值,
 //所以用通用类型Object接收(void也是特殊类型的返回值)
 //stop  stopwatch
 }
}
==Advicer扩展==================================================
给advice传递参数
方式1 用来获取相应的参数进行判断或记录
@Before("com.xyz.myapp.SystemArchitecture.dateAccessOperation() && args(account,..)")//account与方法参数的名称一致
public void validateAccount(Account account) {
 System.out.println("Before.");
}
方式2(与方式1等效)
@Pointcut("com.xyz.myapp.SystemArchitecture.dateAccessOperation() && args(account,..)")//account与方法参数的名称一致
public void accountDataAccessPoeration(Account account) {}

@Before("accountDataAccessPoeration(account)")
public void validateAccount(Account account) {
 System.out.println("Before.");
}

方式3:作用1 记录 2 判断方法用了哪些注解或者注解的值,根据注解的不同或注解value的不同,可以做一些前置的操作
1)定义一个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable { 
 AuditCode value();
}
2)使用该注解
@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void auditAuditable auditable){
 AuditCode code = auditable.value();
 //System.out.println("Before.");
}

===Advice的参数及泛型=================================================
·Spring AOP可以处理泛型类的声明和使用方法的参数
public interface Sample<T> {
 void sampleGenericMethod(T param);
 void sampleGenericCollectionMethod(Collection<T> param);
}

@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
 //advice implementation
}
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleGenericCollectionMethod(Collection<MyType> param) {
 //advice implementation
}
===Advice参数名称=================================================
通知和切入点注解有一个额外的"argNames"属性,它可以用来指定所注解的方法的参数名

@Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditble)",
 argNames="bean,auditable")
public void audit(Object bean,Auditable auditable){
 AuditCode code = auditable.value();
 //...use code and bean
}
如果第一个参数是JoinPoint,ProceedingJoinPoint,JoinPoint.StaticPart,那么可以忽略它
@Before(value = "com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditble)",
 argNames="bean,auditable")
public void audit(JoinPoint jp,Object bean,Auditable auditable){
 AuditCode code = auditable.value();
 //...use code and bean
}
===Introductions=======================================================
·允许一个切面声明一个通知对象实现指定接口,并且提供了一个接口实现类来代表这些对象
·introduction使用@DeclareParents进行注解,这个注解用来定义匹配的类型拥有ige新的parent
例如:给定一个接口UsageTracked,并且该接口拥有DefaultUsageTracked的实现,
接下来的切面声明了所有service皆苦的实现都实现了UsageTracked接口

@Aspect
public class UsageTracking {
 @DeclareParents(value="com.xzy.myapp.service.*+",defaultImpl="DefaultUsageTracked.class")
 public static UsageTracked mixin;
 @Before("com.xyz.myapp.SystemArchitecture.bussinessService() && this(usageTracked)")
 public void recordUsage(UsageTracked usageTracked) {
  usageTracked.incrementUseCount();
 }
}
====切面实例化模型===================================
·这是一个高级主题
·"perthis"切面通过指定@Aspect注解perthis子句实现
·每个独立的service对象执行时都会创建一个切面实例
·service对象的每个方法在第一次执行的时候创捷切面实例,切面在service对象失效的同事失效

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {

 private int someState;

 @Before("com.xyz.myapp.SystemArchitecture.bussinessService()")
 public void recordServiceUsage () {
  //...
 }
}


====================================================
====================================================

定义注解

 1 package com.imooc.aop.aspectj;
 2 import java.lang.annotation.ElementType;
 3 import java.lang.annotation.Retention;
 4 import java.lang.annotation.RetentionPolicy;
 5 import java.lang.annotation.Target;
 6 @Retention(RetentionPolicy.RUNTIME)
 7 @Target(ElementType.METHOD)
 8 public @interface MoocMethod {
 9  
10  String value();
11 }

 


====================================================
例子

 1 package com.imooc.aop.aspectj;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 import org.aspectj.lang.annotation.After;
 5 import org.aspectj.lang.annotation.AfterReturning;
 6 import org.aspectj.lang.annotation.AfterThrowing;
 7 import org.aspectj.lang.annotation.Around;
 8 import org.aspectj.lang.annotation.Aspect;
 9 import org.aspectj.lang.annotation.Before;
10 import org.aspectj.lang.annotation.Pointcut;
11 import org.springframework.stereotype.Component;
12 
13 @Component
14 @Aspect
15 public class MoocAspect {
16     
17     //a    @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..)) && @annotation(moocMethod)")
18     //a    public void pointcut(MoocMethod moocMethod) {}
19     @Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
20     public void pointcut() {}
21     
22     @Pointcut("within(com.imooc.aop.aspectj.biz.*)")
23     public void bizPointcut() {}
24     
25     @Before("pointcut()")// pointcut()方法上面声明了一种类型的pointcut,此处可以使用代替@Before("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")表达式
26     public void before() {
27         System.out.println("Before.");
28     }
29     
30     @Before("pointcut() && args(arg)")
31     public void beforeWithParam(String arg) {
32         System.out.println("BeforeWithParam." + arg);
33     }
34     
35     @Before("pointcut() && @annotation(moocMethod)")
36     //a    @Before("pointcut(moocMethod)")
37     public void beforeWithAnnotaion(MoocMethod moocMethod) {
38         System.out.println("BeforeWithAnnotation." + moocMethod.value());
39     }
40     
41     @AfterReturning(pointcut="bizPointcut()", returning="returnValue")
42     public void afterReturning(Object returnValue) {
43         System.out.println("AfterReturning : " + returnValue);
44     }
45     
46     @AfterThrowing(pointcut="pointcut()", throwing="e")
47     public void afterThrowing(RuntimeException e) {
48         //e.printStackTrace();//调试时,可以打印出堆栈信息
49         System.out.println("AfterThrowing : " + e.getMessage());
50     }
51     
52     @After("pointcut()")
53     public void after() {
54         System.out.println("After.");
55     }
56 
57     @Around("pointcut()")
58     public Object around(ProceedingJoinPoint pjp) throws Throwable {
59         System.out.println("Around 1.");
60         Object obj = pjp.proceed();
61         System.out.println("Around 2.");
62         System.out.println("Around : " + obj);
63         return obj;
64     }
65     
66 }

 

 


==xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans 
 7         http://www.springframework.org/schema/beans/spring-beans.xsd  
 8         http://www.springframework.org/schema/context
 9         http://www.springframework.org/schema/context/spring-context.xsd
10         http://www.springframework.org/schema/aop 
11         http://www.springframework.org/schema/aop/spring-aop.xsd">
12         
13         <context:component-scan base-package="com.imooc.aop.aspectj"/>
14       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
15  </beans>

 

==biz

 

 1 package com.imooc.aop.aspectj.biz;
 2 import org.springframework.stereotype.Service;
 3 import com.imooc.aop.aspectj.MoocMethod;
 4 @Service
 5 public class MoocBiz {
 6  
 7  @MoocMethod("MoocBiz save with MoocMethod.")//给注解赋值
 8  public String save(String arg) {
 9   System.out.println("MoocBiz save : " + arg);
10 //  throw new RuntimeException(" Save failed!");
11   return " Save success!";
12  }
13 }


==Test

 1 package com.imooc.test.aop.aspectj;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.junit.runners.BlockJUnit4ClassRunner;
 5 import com.imooc.aop.aspectj.biz.MoocBiz;
 6 import com.imooc.test.base.UnitTestBase;
 7 @RunWith(BlockJUnit4ClassRunner.class)
 8 public class TestAspectJ extends UnitTestBase {
 9  
10  public TestAspectJ() {
11   super("classpath:spring-aop-aspectj.xml");
12  }
13  
14  @Test
15  public void test() {
16   MoocBiz biz = getBean("moocBiz");
17   biz.save("This is test.");
18  }
19  
20 }

 

posted @ 2017-04-06 10:55  charles999  阅读(308)  评论(0编辑  收藏  举报