文章目录
源码地址:https://github.com/nieandsun/spring-study
这周加班好累啊,今天几乎睡了一天,仍然感觉没有歇过来 ::>_<::
但生活还得继续 。。。
1 AOP使用简介
1.1 前期准备
(1) 导包 — > 可以查看本篇文章对应的commit记录
(2) 业务类并将其注入spring容器
- 业务类
package com.nrsc.springstudy.c10_AOP.service;
import org.springframework.stereotype.Service;
@Service
public class Calculator {
//业务方法
public int div(int i, int j) {
System.err.println("==开始进入div方法===");
return i / j;
}
}
- 配置类
package com.nrsc.springstudy.c10_AOP.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(value = "com.nrsc.springstudy.c10_AOP")
@EnableAspectJAutoProxy//开启AOP功能
public class C10Config {
}
- 启动类
import com.nrsc.springstudy.c10_AOP.config.C10Config;
import com.nrsc.springstudy.c10_AOP.service.Calculator;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test10_AOP {
@Test
public void test01() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(C10Config.class);
Calculator bean = ac.getBean(Calculator.class);
int div = bean.div(4, 2);
System.err.println("=====结果为=======" + div);
ac.close();
}
}
1.2 切面类开发
package com.nrsc.springstudy.c10_AOP.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/***
* 前置通知: 在执行目标方法div()之前运行------------------------------------@Before
* 后置通知: 在目标方法div运行结束之后运行 ,不管有没有异常-------------------@After
* 返回通知: 在目标方法div正常返回值后运行----------------------------------@AfterReturning
* 异常通知: 在目标方法div出现异常后运行------------------------------------@AfterThrowing
*
* 环绕通知: 需要手动执行joinPoint.procced()(其实就是执行目标方法div,),
* 执行joinPoint.procced()之前的方法相当于前置通知,
* 执行之后就相当于后置通知----------------------------@Around
*/
@Aspect
@Component
public class LogAspects {
@Pointcut("execution(public int com.nrsc.springstudy.c10_AOP.service.Calculator.*(..))")
public void pointCut() {
}
@Before("pointCut()") //前置通知
public void logStart(JoinPoint joinPoint) {
//获取到请求参数列表
Object[] args = joinPoint.getArgs();
//获取到请求方法
String name = joinPoint.getSignature().getName();
System.out.println("@Before:当前方法为:" + name + "======参数列表是:" + Arrays.asList(args));
}
@After(value = "pointCut()") //后置通知
public void logEnd(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();
System.out.println("@After---" + name + "方法结束......");
}
@AfterReturning(value = "pointCut()", returning = "result") //返回通知
public void logReturn(Object result) {
System.out.println("@AfterReturning---正常返回......运行结果是:{" + result + "}");
}
@AfterThrowing(value = "pointCut()", throwing = "exception") //异常通知
public void logException(Exception exception) {
System.out.println("@AfterThrowing运行异常......异常信息是:{" + exception + "}");
}
@Around("pointCut()") //环绕通知 --- 工作中我习惯用这个
public Object Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("@Arount:执行目标方法之前...");
//相当于开始调div地
Object obj = proceedingJoinPoint.proceed();
System.out.println("@Arount:执行目标方法之后...");
return obj;
}
}
2 运行结果测试
2.1 目标方法不会发生异常时
启动类中的参数传入的是(4,2)时,运行结果如下图。可以看到各个方法的执行顺序为:
环绕通知 — > 前置通知 —> 目标方法 —> 环绕通知 —> 后置通知 —> 返回通知
由于没有发生异常,所以异常通知没有执行。
2.2 目标方法发生异常,但环绕通知将异常抛出时
(2)当启动类中的参数传入的是(4,0)时,运行结果如下图。可以看到各个方法的执行顺序为:
环绕通知 — > 前置通知 —> 目标方法 —> 后置通知 —> 异常通知
由于发生了异常,返回通知没有执行
下图中异常通知后打印的的红色内容是环绕通知抛出的Throwable 异常信息。
2.3 目标方法发生异常,但环绕通知将异常捕获处理时
在1中我把环绕通运行proceed() 方法可能出现的异常给抛了出去,这种情况下会得到2.2中的运行结果,那假如环绕通知将异常捕获并进行处理,会发生什么呢?
- 环绕通知代码修改
@Around("pointCut()") //环绕通知 --- 工作中我习惯用这个
public Object Around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("@Arount:执行目标方法之前...");
//相当于开始调div地
Object obj = null;
try {
obj = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
System.out.println("@Around运行异常......异常信息是:{" + throwable.getMessage() + "}");
//throwable.printStackTrace();
}
System.out.println("@Arount:执行目标方法之后...");
return obj;
}
启动类中的传入的参数仍是(4,0)时,运行结果如下图。可以看到各个方法的执行顺序为:
环绕通知 — > 前置通知 —> 目标方法 —> 环绕通知 —> 后置通知 —> 返回通知
可以看到这时异常通知方法不会运行
但由于返回参数类型不对,仍然发生了信息报错,导致启动类中的 System.err.println("=结果为===" + div);
方法没有运行。