基于注解的AOP各种通知的使用
AOP的实现基于动态代理,使用的注意事项:
切面类和目标类都需要交给IOC容器管理
切面类必须通过@Aspect注解标识为一个切面
在spring配置文件中设置aop:aspectj-autoproxy/开启基于注解的AOP
AOP实现的重点
1.在切面中,需要通过指定的注解将方法标识为通知方法(以下按执行顺序)
@Before:前置通知,在目标对象方法执行之前执行
@AfterReturning:返回通知,在目标对象方法返回之后执行
@AfterThrowing:异常通知,在出现异常时执行
@After:后置通知,在目标对象方法的Finnally字句中执行
2.切入点表达式:设置在标识通知的注解的value属性中
@Before(“execution(public int com.qcw.spring.aop.annotation.CalculatorImpl.add(int ,int))”)
@Before("execution(* com.qcw.spring.aop.annotation.CalculatorImpl.(…))")
第一行的写法是写死的,只针对add方法 第二行是用于所有方法
第一个表示任意的访问修饰符和返回类型
第二个表示类中任意的方法
…表示任意的参数列表
类的地方也可以使用,表示包下所有的类
3.重用切入点表达式
//@Pointcut:声明一个公共的切入点表达式
@Pointcut(“execution(* com.qcw.spring.aop.annotation.CalculatorImpl.*(…))”)
public void pointCut(){}
使用方法:比如:@Before(“pointCut()”)
4.获取连接点的信息
在通知方法的参数位置,设置joinPoint类型的参数,就可以获取连接点所对应的方法的信息
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
以下是实现过程具体的代码:
package com.qcw.spring.aop.annotation;
public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}
package com.qcw.spring.aop.annotation;
import org.springframework.stereotype.Component;
@Component
public class CalculatorImpl implements Calculator{
public int add(int i, int j) {
int result = i + j;
System.out.println("方法内部,result:"+ result);
return result;
}
public int sub(int i, int j) {
int result = i - j;
System.out.println("方法内部,result:"+ result);
return result;
}
public int mul(int i, int j) {
int result = i * j;
System.out.println("方法内部,result:"+ result);
return result;
}
public int div(int i, int j) {
int result = i / j;
System.out.println("方法内部,result:"+ result);
return result;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
AOP的注意事项
切面类和目标类都需要交给IOC容器管理
切面类必须通过@Aspect注解标识为一个切面
在spring配置文件中设置<aop:aspectj-autoproxy/>开启基于注解的AOP
-->
<context:component-scan base-package="com.qcw.spring.aop.annotation"></context:component-scan>
<!--开启基于注解的AOP-->
<aop:aspectj-autoproxy/>
</beans>
package com.qcw.spring.aop.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 1.在切面中,需要通过指定的注解将方法标识为通知方法(以下按执行顺序)
* @Before:前置通知,在目标对象方法执行之前执行
* @AfterReturning:返回通知,在目标对象方法返回之后执行
* @AfterThrowing:异常通知,在出现异常时执行
* @After:后置通知,在目标对象方法的Finnally字句中执行
*
* 2.切入点表达式:设置在标识通知的注解的value属性中
* @Before("execution(public int com.qcw.spring.aop.annotation.CalculatorImpl.add(int ,int))")
* @Before("execution(* com.qcw.spring.aop.annotation.CalculatorImpl.*(..))")
* 第一行的写法是写死的,只针对add方法 第二行是用于所有方法
* 第一个*表示任意的访问修饰符和返回类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有的类
*
* 3.重用切入点表达式
* //@Pointcut:声明一个公共的切入点表达式
* @Pointcut("execution(* com.qcw.spring.aop.annotation.CalculatorImpl.*(..))")
* public void pointCut(){}
* 使用方法:比如:@Before("pointCut()")
*
* 4.获取连接点的信息
* 在通知方法的参数位置,设置joinPoint类型的参数,就可以获取连接点所对应的方法的信息
* //获取连接点对应方法的签名信息
* Signature signature = joinPoint.getSignature();
* //获取连接点所对应方法的参数
* Object[] args = joinPoint.getArgs();
*/
@Component
@Aspect //将当前组件标识为一个切面
public class LoggerAspect {
@Pointcut("execution(* com.qcw.spring.aop.annotation.CalculatorImpl.*(..))")
public void pointCut(){}
//@Before("execution(public int com.qcw.spring.aop.annotation.CalculatorImpl.add(int ,int))")
//@Before("execution(* com.qcw.spring.aop.annotation.CalculatorImpl.*(..))")
@Before("pointCut()")
public void beforeAdviceMethod(JoinPoint joinPoint){
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect,方法:"+signature.getName()+",参数"+ Arrays.toString(args));
}
/**
* 在返回通知中若要获取目标对象的返回值
* 只需要通过@AfterReturning注解的returning属性
* 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
*/
@AfterReturning(value = "pointCut()",returning = "result")
public void afterReturningAdviseMethod(JoinPoint joinPoint,Object result){
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:"+signature.getName()+",结果:"+result);
}
/**
* 在异常通知中若要获取目标对象方法的异常
* 只需要通过@AfterThrowing注解的throwing属性
* 就可以将通知方法的某个参数指定为接收目标对象方法出现异常的参数
*/
@AfterThrowing(value = "pointCut()",throwing = "ex")
public void afterThrowingAdviceMethod(JoinPoint joinPoint, Throwable ex){
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:"+signature.getName()+",异常:"+ex);
}
@After("pointCut()")
public void afterAdviceMethod(JoinPoint joinPoint){
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect,方法:"+signature.getName()+",执行完毕");
}
}
最后附上测试方法:
package com.qcw.spring.test;
import com.qcw.spring.aop.annotation.Calculator;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
@Test
public void testAOPByAnnotation(){
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("aop-annotation.xml");
Calculator calculator = ioc.getBean(Calculator.class);
calculator.div(1,2);
}
}