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 }