1. 程式人生 > 實用技巧 >SpringBoot面向切面程式設計(AOP)

SpringBoot面向切面程式設計(AOP)

Aspect

(與SpringBoot整合)

總結

  1. 作用位置

    try{
    	try{
    		@Around 前置環繞通知
    		@Before 前置通知
    		method.invoke(..);
           }catch(){
            @AfterThrowing 異常通知
    		throw.....;
       }finally{
    		@After 後置通知
       }
    	@AfterReturning 返回通知
    }finally{
        @Around 後置環繞通知
    }
    
  2. 執行流程

    1. 正常情況: @Around ==> @Before ==> 目標方法 ==> @After ==> @AfterReturning ==> @Around;
    2. 異常情況: @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()執行後----------------------------
後置環繞通知!!!
************************************************************************************************