技术说明:
示意图如下所示:

动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口,因为这个技术要求代理对象额目标对象实现同样的接口
cglib:通过继承被代理的目标类实现代理,所有不需要目标类实现接口
AspectJ:本质上是静态代理,将代理逻辑"织入"被代理的目标类编译得到的字节码文件,所有最终效果是动态的,weaver就是织入器,Spring只是借用了AspectJ中的注解
准备工作
新创建一个Maven

在pom.xml文件中引入依赖

将之前的接口和目标类复制到main的java中

创建切面类

创建一个配置文件

在目标文件中引用之前的目标文件,并添加@Component注解

在切面类添加@Component和@Aspect注解

在配置文件中添加扫描组件进行扫描注解

前置通知
在切面类中通过指定的注解(@Before)将方法标识为通知方法

在spring-annotation的配置文件中添加扫描组件和基于AOP注解的功能

在测试类中添加测试方法

测试结果如下所示:

切入点表达式的语法和重用以及获取连接点的信息
优化切入点表达式:
在切面类中修改:

测试方法如下所示:

测试结果如下所示:

对切面类的方法进行优化:

测试结果如下:

对切入点表达式的重用

后置通知+返回通知+异常通知+环绕通知
在切面中,需要通过指定的注解将方法标识为通知方法:
@Before:前置通知,在目标对象方法执行之前执行
@After:后置通知,在目标对象方法的finally字句中执行
@AfterReturning:后置通知,在目标对象方法返回值之后执行
@AfterThrowing:异常通知,在目标对象方法的catch字句中执行
@Around:环绕通知,
在切面类中添加通知的方法
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
//添加公共的切入点表达式
/*
* @Pointcut:声明一个公共的切入点表达式
* 使用方式:@After("pointCut()")
* */
@Pointcut("execution(* com.spring.pojo.test.aop.annotation.CalculatorImpl.*(..))")
public void pointCut(){
}
@After("pointCut()")//加入切入点表达式
public void AfterAdviceMethod(JoinPoint joinPoint){
System.out.println("LoggerAspect,后置通知");
Signature signature = joinPoint.getSignature();
String name = signature.getName();
Object[] args = joinPoint.getArgs();
System.out.println("方法名:" + name);
System.out.println("参数列表:" + Arrays.toString(args));
}
/*
* 在切面中,需要通过指定的注解将方法标识为通知方法
* @Before:前置通知,在目标对象方法执行之前执行
* */
// @Before("execution(public int com.spring.test.aop.annotation.CalculatorImpl.add(int,int))")//切入点表达式
/*
* 切入点表达式的优化:
* 切入点表达式设置在表示通知的注解的value属性中
* 第一个*代表:任意的访问修饰符和任意的返回类型
* 第二个*代表:当前类中的任意方法
* ..代表:任意的参数列表
* 类所在的地方也可以使用*,表示包下所有的类
* */
@Before("execution(* com.spring.pojo.test.aop.annotation.CalculatorImpl.*(..))")
/*
* 获取连接点的信息:
* 在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
*
* */
public void beforeAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取方法名
String name = signature.getName();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect,前置通知");
System.out.println("LoggerAspect,方法名:" + name);
System.out.println("LoggerAspect,参数:" + Arrays.toString(args));
}
//返回通知
/*
*在返回通知中获取目标对象方法的返回值,只需要通过@AfterReturning注解的returning属性
*就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
*
* */
@AfterReturning(value = "pointCut()",returning = "result" )
public void afterReturningAdviceMethod(JoinPoint joinPoint,Object result){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("返回通知-方法名: " + name);
System.out.println("返回通知-结果:" + result);
System.out.println("LoggerAspect,返回通知");
}
//异常通知
/*
* 在异常通知中若需要获取目标对象方法的异常,只需要通过@AfterThrowing注解的throwing属性
*就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
* */
@AfterThrowing(value = "pointCut()" ,throwing = "throwable")
public void afterThrowingAdviceMethod(JoinPoint joinPoint,Throwable throwable ){
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println("异常通知-方法名 :" +name);
System.out.println("异常:" + throwable);
System.out.println("LoggerAspect,异常通知");
}
//环绕通知
@Around("pointCut()")
//环绕通知方法的返回值一定要和目标对象方法的返回值一致
public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
Object result = null;
try {
System.out.println("环绕通知->前置通知");
//表示目标对象方法的执行
result = joinPoint.proceed();
System.out.println("环绕通知->返回通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("环绕通知->异常通知");
}finally {
System.out.println("环绕通知->后置通知");
}
return result;
}
测试结果如下:
后置通知:
测试方法:

测试结果:
返回通知:
测试结果:
异常通知:
测试方法:
测试结果:
环绕通知:
测试方法:
测试结果:

922

被折叠的 条评论
为什么被折叠?



