Spring AOP基础
目录
AOP基本术语
Advice-通知
Before
前置通知,目标方法被调用前调用
After
后置通知,目标方法完成后调用通知,并不关心方法的输出是什么
After-returning
目标方法成功执行后调用
After-throwing
目标方法抛出异常后调用
Around
通知包裹了被通知的方法,在被通知的方法调用前和调用后执行自定义行为
Pointcut-切点
定义哪些方法是需要被通知的
Aspect-切面
Advice+Pointcut=Aspect
Join Point-连接点
应用执行过程中能够插入切面的时间点
如:抛出异常时、调用方法时......
Introduction-引入
向现有类添加新的方法或属性
Weaving-织入
把切面应用到目标对象并创建新的代理对象
切点详解
Spring的AOP中,使用AspectJ切点表达式来定义切点
Spring仅支持AspectJ切点指示器的一个子集
arg()
指定方法的参数类型
@args()
指定方法的参数由指定注解标注
execution()
指定方法,方法由切点表达式描述 (* 包名.类名.方法名(参数))
- 表示返回任意类型
参数如果是 .. ,表示任意参数
within()
指定方法类型
@within()
指定方法的注解类型
@annotation()
指定方法带有指定注解
其他
bean()
bean("beanId")-在指定bean中生效
!bean("beanId")-在指定bean中不生效
切点之间可以使用 &&、||、!连接,如果在xml中描述,使用 and、or、not
定义切面
package com.zln.aop;
import org.aspectj.lang.annotation.*;
/**
* 定义切面
* Created by sherry on 17/3/9.
*/
@Aspect
public class Audience {
/**
* 切点
*/
@Pointcut("execution(* com.zln.aop.Performance.*(..))")
public void performance(){}
/**
* 前置通知
*/
@Before("performance()")
public void silenceCellPhones(){
System.out.println("前置通知:表演前手机静音");
}
@Before("performance()")
public void takeSeats(){
System.out.println("前置通知:就坐");
}
@AfterReturning("performance()")
public void applause(){
System.out.println("返回通知:表演结束,鼓掌");
}
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("异常通知:表演失败");
}
}
package com;
import com.zln.aop.Audience;
import org.springframework.context.annotation.*;
/**
* Created by sherry on 17/3/9.
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppBeans {
@Bean
public Audience audience(){
return new Audience();
}
}
运行测试
package com.zln.aop;
import org.springframework.stereotype.Component;
/**
* Created by sherry on 17/3/9.
*/
@Component
public class Performance{
public void perform() {
System.out.println("正在表演");
}
}
环绕通知
package com.zln.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* 定义切面
* Created by sherry on 17/3/9.
*/
@Aspect
public class Audience {
/**
* 切点
*/
@Pointcut("execution(* com.zln.aop.Performance.*(..))")
public void performance(){}
/**
* 前置通知
*/
@Before("performance()")
public void silenceCellPhones(){
System.out.println("前置通知:表演前手机静音");
}
@Before("performance()")
public void takeSeats(){
System.out.println("前置通知:就坐");
}
@AfterReturning("performance()")
public void applause(){
System.out.println("返回通知:表演结束,鼓掌");
}
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("异常通知:表演失败");
}
@Around("performance()")
public void watch(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("环绕通知1");
try {
proceedingJoinPoint.proceed();
System.out.println("环绕通知2");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
环绕通知的proceedingJoinPoint.proceed();比较神奇,如果没有这句,相当于代码阻塞,如果调用多次,相当于执行多次目标方法
通知的方法参数
package com.zln.aop;
import org.springframework.stereotype.Component;
/**
* Created by sherry on 17/3/9.
*/
@Component
public class Performance{
public void perform(int i) {
System.out.println("正在表演");
}
}
//如果不是int等基本类型,要使用类的全限定名
@Pointcut("execution(* com.zln.aop.Performance.*(int))")
public void performance(){}
/**
* 前置通知
*/
@Before("performance()&&args(i)")
public void silenceCellPhones(int i){
System.out.println("前置通知:表演前手机静音"+i);
}
调用perform方法的时候,参数i的值就会被获取到