Aspect
(與SpringBoot整合)
總結
-
作用位置
try{ try{ @Around 前置環繞通知 @Before 前置通知 method.invoke(..); }catch(){ @AfterThrowing 異常通知 throw.....; }finally{ @After 后置通知 } @AfterReturning 返回通知 }finally{ @Around 后置環繞通知 }
-
執行流程
- 正常情況: @Around ==> @Before ==> 目標方法 ==> @After ==> @AfterReturning ==> @Around;
- 異常情況: @Around ==> @Before ==> 目標方法(出現異常) ==> @AfterThrowing ==> @After ==> @Around;
代碼演示
1. 引入aop依賴
pom.xml
<!-- 引入AOP依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 核心業務類
Service層
UserService.java
@Service
public class UserService {
public void service1(){
System.out.println("Service-1-執行");
}
public String service2(){
System.out.println("Service-2-執行");
//int i = 1/0; //異常測試
return "Success!!!";
}
public ArrayList<String> service3(String userName){
System.out.println("Service-3-執行");
ArrayList<String> list = new ArrayList<>();
list.add("Service-3-執行成功!!!");
list.add(userName);
return list;
}
}
3. 切面
MyAspect.java
注:一定要將切面作為Spring組件注入容器
@Component
@Aspect
public class MyAspect {
//定義切入點
@Pointcut("within(com.juyss.service.*)")
public void pointcut(){}
//環繞通知 ===> 正常情況執行在@Before和@After之前,如果執行過程中拋異常,只執行前置環繞通知,后置環繞不執行
@Around(value = "pointcut()")
public Object around(ProceedingJoinPoint point){
System.out.println("前置環繞通知!!!");
Object proceed = null;
try {
System.out.println("point.proceed()執行前----------------------------");
Signature signature = point.getSignature();
System.out.println("獲取類名:"+signature.getName());
System.out.println("point.proceed()執行前----------------------------");
proceed = point.proceed();
System.out.println("point.proceed()執行后----------------------------");
System.out.println("獲取返回值:"+proceed);
System.out.println("point.proceed()執行后----------------------------");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("后置環繞通知!!!");
return proceed;
}
//前置通知 ===> 方法執行前
@Before("pointcut()")
public void before(){
System.out.println("前置通知生效!!!");
}
//返回通知 ===> 方法正常執行完后執行,可以獲取返回值.如果方法執行過程中拋異常,則不會執行
@AfterReturning(value = "pointcut()",returning = "returnValue")
public void afterReturning(Object returnValue){
System.out.println("返回通知生效!!! ------返回值:"+returnValue);
}
//后置通知 ===> 在finally代碼塊中執行,無論如何都會執行的通知
@After("pointcut()")
public void after(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
System.out.println("后置通知生效!!! ------ 方法名:"+signature.getName());
}
//異常通知 ===> 在執行過程中拋出異常時執行
@AfterThrowing(value = "pointcut()",throwing = "e")
public void afterThrowing(Exception e){
System.out.println("異常通知生效!!! 異常信息:"+e.getMessage());
}
}
4. 測試類
AspectApplicationTests.java
@SpringBootTest
class AspectApplicationTests {
@Autowired
private UserService service;
@Test
public void Test(){
service.service1();
System.out.println("************************************************************************");
service.service2();
System.out.println("************************************************************************");
service.service3("方法參數");
System.out.println("************************************************************************");
}
}
5. 測試結果
正常運行時:
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service1
point.proceed()執行前----------------------------
前置通知生效!!!
Service-1-執行
返回通知生效!!! ------返回值:null
后置通知生效!!! ------ 方法名:service1
point.proceed()執行后----------------------------
獲取返回值:null
point.proceed()執行后----------------------------
后置環繞通知!!!
************************************************************************************************
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service2
point.proceed()執行前----------------------------
前置通知生效!!!
Service-2-執行
返回通知生效!!! ------返回值:Success!!!
后置通知生效!!! ------ 方法名:service2
point.proceed()執行后----------------------------
獲取返回值:Success!!!
point.proceed()執行后----------------------------
后置環繞通知!!!
************************************************************************************************
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service3
point.proceed()執行前----------------------------
前置通知生效!!!
Service-3-執行
返回通知生效!!! ------返回值:[Service-3-執行成功!!!, 方法參數]
后置通知生效!!! ------ 方法名:service3
point.proceed()執行后----------------------------
獲取返回值:[Service-3-執行成功!!!, 方法參數]
point.proceed()執行后----------------------------
后置環繞通知!!!
************************************************************************************************
方法運行拋出異常時
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service1
point.proceed()執行前----------------------------
前置通知生效!!!
Service-1-執行
返回通知生效!!! ------返回值:null
后置通知生效!!! ------ 方法名:service1
point.proceed()執行后----------------------------
獲取返回值:null
point.proceed()執行后----------------------------
后置環繞通知!!!
************************************************************************************************
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service2
point.proceed()執行前----------------------------
前置通知生效!!!
Service-2-執行
異常通知生效!!! 異常信息:/ by zero
后置通知生效!!! ------ 方法名:service2
java.lang.ArithmeticException: / by zero
at com.juyss.service.UserService.service2(UserService.java:25)
##############其他異常信息省略################
后置環繞通知!!!
************************************************************************************************
前置環繞通知!!!
point.proceed()執行前----------------------------
獲取類名:service3
point.proceed()執行前----------------------------
前置通知生效!!!
Service-3-執行
返回通知生效!!! ------返回值:[Service-3-執行成功!!!, 方法參數]
后置通知生效!!! ------ 方法名:service3
point.proceed()執行后----------------------------
獲取返回值:[Service-3-執行成功!!!, 方法參數]
point.proceed()執行后----------------------------
后置環繞通知!!!
************************************************************************************************