Spring基礎系列--AOP實踐

來源:互聯網
上載者:User

原創作品,可以,但是請標註出處地址:www.cnblogs.com/V1haoge/p/9615720.html 

  本文目的是簡單講解下Spring AOP的使用。

  推薦使用IDEA + Spring Boot。

  建立Spring Boot 項目,選擇Aspect功能。

  建立完成後,POM檔案如下:

 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4     <modelVersion>4.0.0</modelVersion> 5  6     <groupId>com.example</groupId> 7     <artifactId>spring-aspect-demo</artifactId> 8     <version>0.0.1-SNAPSHOT</version> 9     <packaging>jar</packaging>10 11     <name>spring-aspect-demo</name>12     <description>Demo project for Spring Boot</description>13 14     <parent>15         <groupId>org.springframework.boot</groupId>16         <artifactId>spring-boot-starter-parent</artifactId>17         <version>2.0.4.RELEASE</version>18         <relativePath/> <!-- lookup parent from repository -->19     </parent>20 21     <properties>22         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>23         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>24         <java.version>1.8</java.version>25     </properties>26 27     <dependencies>28         <dependency>29             <groupId>org.springframework.boot</groupId>30             <artifactId>spring-boot-starter-aop</artifactId>31         </dependency>32 33         <dependency>34             <groupId>org.springframework.boot</groupId>35             <artifactId>spring-boot-starter-test</artifactId>36             <scope>test</scope>37         </dependency>38     </dependencies>39 40     <build>41         <plugins>42             <plugin>43                 <groupId>org.springframework.boot</groupId>44                 <artifactId>spring-boot-maven-plugin</artifactId>45             </plugin>46         </plugins>47     </build>48 49 50 </project>

  然後我們建立目標類和方法:

 1 package com.example.springaspectdemo; 2  3 import org.springframework.stereotype.Component; 4  5 @Component 6 public class AspectDemo { 7     public Integer test(String s){ 8         System.out.println("目標方法執行-"+s); 9         return 123321;10     }11 }

  上面的代碼中主要的就是@Component註解,在於將目標類掃描到Spring容器中。

  下面我們建立切面類:

 1 package com.example.springaspectdemo; 2  3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 import org.aspectj.lang.annotation.*; 6 import org.springframework.stereotype.Component; 7  8 @Aspect 9 @Component10 public class AspectTest {11 12     @Pointcut(value = "execution(* *.test(..)) && args(s)")13     public void pc(String s){14         System.out.println("切點執行");15     }16 22     @Before("pc(s)")23     public void beforeTest(JoinPoint jp,String s){24         System.out.println("前置通知-arg="+s);25     }26 27     @After("pc(s)")28     public void afterTest(String s){29         System.out.println("後置終點通知-arg="+s);30     }31 32     @AfterReturning(pointcut = "pc(s)", returning = "i")33     public void afterReturningTest(Object i,String s){34         System.out.println("後置返回通知-return="+i+"-arg="+s);35     }36 37     @AfterThrowing(pointcut = "pc(s)",throwing = "e")38     public void afterThrowingTest(Exception e,String s){39         System.out.println("後置異常通知-"+e.getMessage()+"-arg="+s);40     }41 42     @Around("pc(s)")43     public void aroundTest(ProceedingJoinPoint jp,String s){44         System.out.println("環繞前置通知-arg="+s);45         Object[] os = jp.getArgs();46         s = "caocao";47         os[0] = s;48         try {49             jp.proceed(os);50         } catch (Throwable throwable) {51             throwable.printStackTrace();52         }53         System.out.println("環繞後置通知-arg="+s);54     }55 }

  建立測試案例:

 1 package com.example.springaspectdemo; 2  3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.test.context.SpringBootTest; 7 import org.springframework.context.annotation.EnableAspectJAutoProxy; 8 import org.springframework.test.context.junit4.SpringRunner; 9 10 @RunWith(SpringRunner.class)11 @SpringBootTest12 @EnableAspectJAutoProxy13 public class SpringAspectDemoApplicationTests {14     @Autowired15     private AspectDemo aspectDemo;16 17     @Test18     public void aspecctTest(){19         aspectDemo.test("huahua");20     }21 }

  執行結果:

環繞前置通知-arg=huahua前置通知-arg=caocao目標方法執行-caocao環繞後置通知-arg=caocao後置終點通知-arg=caocao後置返回通知-return=null-arg=caocao

  重點解析:

  1、後置返回通知是在目標代碼執行完畢,返回結果之後執行,可以對返回的結果進行處理,但是要注意,其不能和環繞通知一起作用於同一個目標方法,否則會導致無法擷取到傳回值,正如上面例子中執行結果最後一行的null,表示的就是傳回值,如果將環繞通知的部分注釋掉,則可以返回正確的結果。

  2、後置返回通知的傳回值類型必須是參考型別或者封裝類型,不能是原始類型,否則會報錯,類型不符。

  3、我們可以對目標方法的參數進行修改,但只能在環繞通知中進行,在環繞通知中的第一個參數必然是ProceedJoinPoint,它是JoinPoint的子類,通過其getArgs方法可以擷取到調用目標方法的參數列表,可以對其進行修改,然後再執行帶參數的proceed方法,將新的參數列表傳遞到目標方法。而且我們可以從上面的執行結果看到,環繞通知的前置部分是先於其他所有通知而執行的,那麼它修改參數之後將會作用於後面所有的通知。正如例子中,我們在環繞通知前置部分將參數"huahua"改成了"caocao",在之後的所有通知和目標方法中擷取到的參數全部變成了"caocao"。

  4、異常通知不只是捕捉目標方法中的異常,還有作用於同一方法上的其他通知中發生的異常。所以並不是一旦出現異常就不會執行afterReturning通知方法。如果是目標方法執行正常,卻在afterReturning中發生異常的話,那麼就會同時執行afterReturning通知方法和afterThrowing通知方法。

  5、我們還可以從上面的執行結果看到各個通知的執行順序:

    環繞通知前置部分--->前置通知--->目標方法--->環繞通知後置部分--->後置終點通知--->後置返回通知--->後置異常通知

  6、對於上面執行的一點補充:

    那就是發生異常的情況,如果在環繞通知前置部分發生異常,那麼之後除了後置終點通知是必然執行的外,只有最後的異常通知會被觸發,其餘一概不會執行。

    如果第5點中執行順序哪一步發生了異常,那麼其前面的通知會正常執行,後面的除了後置終點通知一定會執行外,異常通知也回被觸發。

    但有一個例外,那就是前置通知,在前置通知和環繞通知同時作用於一個目標方法時,前置通知的異常將不會被後置異常通知捕捉到。

  7、終上所述,推薦不要將環繞通知和其他通知一起使用。因為環繞通知會導致一些異常的情況,使其他通知的部分功能失效。

  可以使用上面的代碼進行修改測試!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.