Java Spring-AOP切面的优先级和切点表达式
2020-01-31 本文已影响0人
一亩三分甜
可以使用@Order注解指定切面的优先级,值越小优先级越高
在同一个连接点上应用不止一个切面时,除非明确指定,否则它们的优先级是不确定的。切面的优先级可以通过实现Ordered接口或利用@Order注解指定。
public interface ArithmeticCalculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {
//声明该方法是一个前置通知:在目标方法开始之前执行
@Before("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(int,int))")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method " + methodName + " begins with" + args);
}
//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
//在后置通知中还不能访问目标方法执行的结果
@After("execution(* com.cloud.spring.aop.impl.*.*(int,int))")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends");
}
/*
* 在方法正常结束之后执行的代码
* 返回通知是可以访问到方法的返回值的!
*/
@AfterReturning(value = "execution(* com.cloud.spring.aop.impl.*.*(..))",returning = "result")
public void afterReturing(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends with " + result);
}
/*
* 在目标方法出现异常时会执行的代码
* 可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
*/
@AfterThrowing(value = "execution(* com.cloud.spring.aop.impl.*.*(..))",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " occurs exception with " + ex);
}
/*
* 环绕通知需要携带ProceedingJointPoint 类型的参数
* 环绕通知类似于动态代理的全过程:ProceedingJointPoint 类型的参数可以决定是否执行目标方法。
* 且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
@Around("execution(* com.cloud.spring.aop.impl.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint pjd){
Object result = null;
String methodName = pjd.getSignature().getName();
try {
//前置通知
System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
//执行目标方法
result = pjd.proceed();
//返回通知
System.out.println("The method " + methodName + " ends with " + result);
}catch (Throwable e){
//异常通知
System.out.println("The method " + methodName + " occurs exception: " + e);
throw new RuntimeException(e);
}
System.out.println("The method " + methodName + " ends ");
return result;
}
}
public class Main {
public static void main(String[] args) {
//1.创建Spring的IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从IOC容器中获取bean的实例
ArithmeticCalculator arithmeticCalculator = context.getBean(ArithmeticCalculator.class);
//3.使用bean
int result = arithmeticCalculator.add(3,6);
System.out.println("result:" + result);
result = arithmeticCalculator.div(9,3);
System.out.println("result:" + result);
}
}
@Order(1)
@Aspect
@Component
public class ValidationAspect {
@Before("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(..))")
public void validateArgs(JoinPoint joinPoint){
System.out.println("--> validate: " + Arrays.asList(joinPoint.getArgs()));
}
}
//输出
Connected to the target VM, address: '127.0.0.1:51995', transport: 'socket'
--> validate: [3, 6]
The method add begins with [3, 6]
The method add begins with[3, 6]
The method add ends with 9
The method add ends
The method add ends
The method add ends with 9
result:9
--> validate: [9, 3]
The method div begins with [9, 3]
The method div begins with[9, 3]
The method div ends with 3
The method div ends
The method div ends
The method div ends with 3
result:3
重用切点表达式:定义一个方法,用于声明切入点表达式,一般地,该方法中再不需要填入其他的代码。使用Pointcut来声明切入点表达式。后面的其他通知直接使用方法名来引用当前的切入点表达式。
//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面
@Order(2)
@Aspect
@Component
public class LoggingAspect {
/*
* 定义一个方法,用于声明切入点表达式。一般地,该方法中再不需要添入其他的代码。
* 使用@Pointcut来声明切入点表达式
* 后面的其他通知直接使用方法名来引用当前的切入点表达式
*/
@Pointcut("execution(public int com.cloud.spring.aop.impl.ArithmeticCalculator.*(..))")
public void declareJointPointExpression(){}
//声明该方法是一个前置通知:在目标方法开始之前执行
@Before("declareJointPointExpression()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method " + methodName + " begins with" + args);
}
//后置通知:在目标方法执行后(无论是否发生异常),执行的通知
//在后置通知中还不能访问目标方法执行的结果
@After("declareJointPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends");
}
/*
* 在方法正常结束之后执行的代码
* 返回通知是可以访问到方法的返回值的!
*/
@AfterReturning(value = "declareJointPointExpression()",returning = "result")
public void afterReturing(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " ends with " + result);
}
/*
* 在目标方法出现异常时会执行的代码
* 可以访问到异常对象,且可以指定在出现特定异常时再执行通知代码
*/
@AfterThrowing(value = "declareJointPointExpression()",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName + " occurs exception with " + ex);
}
/*
* 环绕通知需要携带ProceedingJointPoint 类型的参数
* 环绕通知类似于动态代理的全过程:ProceedingJointPoint 类型的参数可以决定是否执行目标方法。
* 且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
@Around("declareJointPointExpression()")
public Object aroundMethod(ProceedingJoinPoint pjd){
Object result = null;
String methodName = pjd.getSignature().getName();
try {
//前置通知
System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
//执行目标方法
result = pjd.proceed();
//返回通知
System.out.println("The method " + methodName + " ends with " + result);
}catch (Throwable e){
//异常通知
System.out.println("The method " + methodName + " occurs exception: " + e);
throw new RuntimeException(e);
}
System.out.println("The method " + methodName + " ends ");
return result;
}
}
//输出
Connected to the target VM, address: '127.0.0.1:52041', transport: 'socket'
--> validate: [3, 6]
The method add begins with [3, 6]
The method add begins with[3, 6]
The method add ends with 9
The method add ends
The method add ends
The method add ends with 9
result:9
--> validate: [9, 3]
The method div begins with [9, 3]
The method div begins with[9, 3]
The method div ends with 3
The method div ends
The method div ends
The method div ends with 3
result:3