SpringBoot切面Aop的demo簡單講解

前言

本篇文章主要介紹的是SpringBoot切面Aop的demo簡單講解。html

SpringBoot Aop

說明:若是想直接獲取工程那麼能夠直接跳到底部,經過連接下載工程代碼。java

切面(Aop)

1、概念git

AOP(Aspect OrientedProgramming):面向切面編程,面向切面編程(也叫面向方面編程),是目前軟件開發中的一個熱點,也是Spring框架中的一個重要內容。利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。github

2、用途web

日誌記錄,性能統計,安全控制,權限管理,事務處理,異常處理,資源池管理。spring

3、詳解編程

1.切面(Aspect):
官方的抽象定義爲「一個關注點的模塊化,這個關注點可能會橫切多個對象」,在本例中,「切面」就是類TestAspect所關注的具體行爲,例如:AServiceImpl.barA()的調用就是切面TestAspect所關注的行爲之一。「切面」在ApplicationContext中aop:aspect來配置。json

2.鏈接點(Joinpoint):
程序執行過程當中的某一行爲,例如,AServiceImpl.barA()的調用或者BServiceImpl.barB(String _msg, int _type)拋出異常等行爲。api

3.通知(Advice):
「切面」對於某個「鏈接點」所產生的動做,例如,TestAspect中對com.spring.service包下全部類的方法進行日誌記錄的動做就是一個Advice。其中,一個「切面」能夠包含多個「Advice」,例如TestAspect。Advice共有以下5種類型:瀏覽器

  • A 前置通知(Before advice) :在某鏈接點(JoinPoint)以前執行的通知,但這個通知不能阻止鏈接點前的執行。xml中在aop:aspect裏面使用aop:before元素進行聲明;例如,TestAspect中的doBefore方法。註解中使用@Before聲明;例如,TestAnnotationAspect中的doBefore方法。
  • B 後通知(After advice):當某鏈接點退出的時候執行的通知(不管是正常返回仍是異常退出)。xml中在aop:aspect裏面使用aop:after元素進行聲明。例如,TestAspect中的doAfter方法,因此AOPTest中調用BServiceImpl.barB拋出異常時,doAfter方法仍然執行。註解中使用@After聲明。
  • C 返回後通知(After return advice):在某鏈接點正常完成後執行的通知,不包括拋出異常的狀況。xml中在aop:aspect裏面使用 元素進行聲明。註解中使用@AfterReturning聲明;
  • D 環繞通知(Around advice) :包圍一個鏈接點的通知,相似Web中Servlet規範中的Filter的doFilter方法。能夠在方法的調用先後完成自定義的行爲,也能夠選擇不執行。xml中在aop:aspect裏面使用aop:around元素進行聲明。例如,TestAspect中的doAround方法。註解中使用@Around聲明。
  • E 拋出異常後通知(After throwing advice) : 在方法拋出異常退出時執行的通知。xml中在aop:aspect裏面使用aop:after-throwing元素進行聲明。例如,TestAspect中的doThrowing方法。註解中使用@AfterThrowing聲明。
  • 通知執行順序:前置通知→環繞通知鏈接點以前→鏈接點執行→環繞通知鏈接點以後→返回通知→後通知 →(若是發生異常)異常通知→後通知。

4.切入點(Pointcut)
匹配鏈接點的斷言,在AOP中通知和一個切入點表達式關聯。例如,TestAspect中的全部通知所關注的鏈接點,都由切入點表達式execution(* com.spring.service..(..))來決定。

注:以上的理論知識參考:http://www.javashuo.com/article/p-xwxfjphd-bt.html

開發準備

環境要求

JDK:1.8

SpringBoot:2.2.6.RELEASE

首先仍是Maven的相關依賴,基本和普通springboot項目同樣,就是多了spring-boot-starter-aop這jar的依賴。

pom.xml文件以下:

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.2.6.RELEASE</version>
	<relativePath/>
</parent>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-aop</artifactId>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.68</version>
	</dependency>
     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
        <scope>test</scope>
	</dependency>
</dependencies>

application.properties的文件的配置:

banner.charset=UTF-8
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8
spring.application.name=springboot-aspect
server.port=8180

代碼編寫

SpringBoot在使用切面的時候,只須要在自定義的一個切面類中加上 @Aspect 註解進行聲明,而後在自定義切面的類方法中加上對應的註解便可。
好比這裏的示例咱們想作一個請求響應的加解密切面處理,業務層只需關心代碼邏輯實現,而不用關心請求參數和響應參數的加解密實現。那麼首先咱們須要自定義一個加解密的切面類,在該類添加@Aspect註解,而後在定義一個公共的切入點(Pointcut),指向須要處理的包,而後在定義一個前置通知(添加@Before註解)和後置通知(添加@AfterReturning)方法實現便可。

這裏咱們就將切入點設置爲控制層包裏全部的請求。

切入點代碼示例:

@Pointcut("execution(public * com.pancm.web.*.*(..))")
  			  public void doOperation() {
   		 }

而後在定義一個前置通知,實現對請求參數的數據解密,這裏咱們就用User這個實體類的名稱,對該數據進行解密。實際在運用是能夠根據自身的狀況來編寫。

前置通知代碼示例:

@Before("doOperation()")
    public void before(JoinPoint joinPoint) throws Throwable{
        Object[] objs = joinPoint.getArgs();
        for (Object obj : objs) {
            User user =(User) obj;
            System.out.println("前置通知接受的參數:"+user);
            String name =base64DeStr(user.getName());
            user.setName(name);
        }
    }

在編寫完前置通知的方法以後,咱們在編寫後置通知的代碼,這塊基本和前置通知的同樣,就是把返回的數據進行加密而已。

後置通知代碼示例:

@AfterReturning(returning = "object", pointcut = "doOperation()")
    public void doAfterReturning(Object object) {
        ResultBody resultBody = (ResultBody) object;
        String str =null;
        try {
             str=base64EnStr(resultBody.getResult());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        resultBody.setResult(str);
        System.out.println("後通知響應的參數:"+resultBody);
    }

完整代碼示例:

@Aspect
@Component
public class ParamAspect {

    @Pointcut("execution(public * com.pancm.web.*.*(..))")
    public void doOperation() {

    }


    @Before("doOperation()")
    public void before(JoinPoint joinPoint) throws Throwable{
        Object[] objs = joinPoint.getArgs();
        for (Object obj : objs) {
            User user =(User) obj;
            System.out.println("前置通知接受的參數:"+user);
            String name =base64DeStr(user.getName());
            user.setName(name);
        }
    }


    @AfterReturning(returning = "object", pointcut = "doOperation()")
    public void doAfterReturning(Object object) {
        ResultBody resultBody = (ResultBody) object;
        String str =null;
        try {
             str=base64EnStr(resultBody.getResult());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        resultBody.setResult(str);
        System.out.println("前置通知響應的參數:"+resultBody);
    }


    public  String base64EnStr(String str) throws UnsupportedEncodingException {
        return Base64.getEncoder().encodeToString(str.getBytes("UTF-8"));
    }


    public static String base64DeStr(String encodeStr) throws UnsupportedEncodingException {
        byte[] decodeStr = Base64.getDecoder().decode(encodeStr);
        return new String(decodeStr, "UTF-8");
    }

實體類代碼

public class User {
		
		 private Long id;
	
		 private String name;
		 
		 private Integer age;
		 
		//getter 和 setter 略
		
	}

控制層z這塊的代碼和普通的同樣,咱們這裏只需簡單的作下處理便可,這裏爲了方便理解,沒有編寫service層和dao的代碼。:

** 控制層代碼**

@RestController
@RequestMapping(value = "/api")
public class UserRestController {

    @GetMapping("/user")
    public ResultBody findByUser(User  user) {
        System.out.println("用戶查詢接口請求的參數:"+user);
        ResultBody resultBody = new ResultBody();
        List<User> userList =new ArrayList<>();
        User user2=new User();
        user2.setId(1L);
        user2.setName("xuwujing");
        user2.setAge(18);
        userList.add(user2);
        resultBody.setCode("0");
        resultBody.setResult(userList.toString());
        System.out.println("用戶查詢接口響應的參數:"+resultBody);
        return resultBody;
    }
}

App 入口

和普通的SpringBoot項目基本同樣!

代碼以下:

@SpringBootApplication
	public class AspectApp
	{
	    public static void main( String[] args )
	    {
			SpringApplication.run(AspectApp.class, args);
			System.out.println("Aspect啓動成功!");
	    }
	}

功能測試

編寫完代碼以後,咱們啓動程序,由於是Get請求,在瀏覽器或者使用Postman輸入地址均可以進行測試,須要注意的是這裏咱們須要對name的值進行base64加密請求。

輸入:

http://localhost:8180/api/user?name=eHV3dWppbmc=

控制檯打印:

前置通知接受的參數:{"name":"eHV3dWppbmc="}
用戶查詢接口請求的參數:{"name":"xuwujing"}
用戶查詢接口響應的參數:{"code":"0","result":"[{"age":18,"id":1,"name":"xuwujing"}]"}
後通知響應的參數:{"code":"0","result":"W3siYWdlIjoxOCwiaWQiOjEsIm5hbWUiOiJ4dXd1amluZyJ9XQ=="}

請求響應參數:

{
"code": "0",
"message": null,
"result": "W3siYWdlIjoxOCwiaWQiOjEsIm5hbWUiOiJ4dXd1amluZyJ9XQ=="
}

示例圖:
在這裏插入圖片描述
在這裏插入圖片描述

其它

關於SpringBoot切面Aop的demo簡單講解的文章就講解到這裏了,若有不妥,歡迎指正!

項目地址

SpringBoot 的aop的項目工程地址:
https://github.com/xuwujing/springBoot-study/tree/master/springboot-aspect

SpringBoot整個集合的地址:
https://github.com/xuwujing/springBoot-study

SpringBoot整合系列的文章

音樂推薦

翩若驚鴻,婉若游龍,榮曜秋菊,華茂春鬆。彷彿兮若輕雲之蔽月,飄飄兮若流風之迴雪。遠而望之,皎若太陽升朝霞;迫而察之,灼若芙蕖出淥波。--網易雲網友評論

原創不易,若是感受不錯,但願給個推薦!您的支持是我寫做的最大動力!
版權聲明:
做者:虛無境
博客園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm    
我的博客出處:http://www.panchengming.com

相關文章
相關標籤/搜索