Spring AOP

来源:https://www.cnblogs.com/chy18883701161/archive/2019/07/04/11135435.html
-Advertisement-
Play Games

目錄 AOP簡介 Spring AOP的2種代理 JDK動態代理 CGLIB代理 AOP簡介 AOP全稱Aspect-Oriented Programming,即面向切麵編程,它是面向對象編程(OOP)的一種補充。 在通常的業務處理中,都會進行事務處理、日誌記錄等操作,比如: 這是一個操作用戶的類, ...


 

目錄

AOP簡介

Spring  AOP的2種代理

 

 

 

AOP簡介

AOP全稱Aspect-Oriented  Programming,即面向切麵編程,它是面向對象編程(OOP)的一種補充。

 

在通常的業務處理中,都會進行事務處理、日誌記錄等操作,比如:

 1 class  User{
 2     public void addUser(){
 3         ......  //添加用戶
 4         ....... //記錄一條日誌:xxx時間添加xxx用戶,操作者:xxx,操作結果:xxx
 5     }
 6 
 7     public  void  alterUser(){
 8         .......  //修改用戶
 9         ........//記錄一條日誌:xxx時間修改xxx用戶,操作者:xxx,操作結果:xxx
10     }
11 
12     public void  deleteUser(){
13         .......//刪除用戶
14         .......//記錄一條日誌:xxx時間刪除xxx用戶,操作者:xxx,操作結果:xxx
15 }

這是一個操作用戶的類,是對用戶的抽象,日誌操作和用戶操作其實沒有半毛錢關係,上面的抽象並不好,把用戶操作和日誌操作雜糅在一起,應該把日誌操作分離出去,這樣才符合OOP的編程思想。

而且後期不好維護、升級,比如後面要修改日誌操作,你找到User類,在addUser()中一部分是用戶操作,一部分是日誌操作,你要先找到哪些是日誌操作,然後改。後面的方法也是如此,很繁瑣。

 

AOP解決了此問題。AOP是一種新的編程思想,是OOP的一種補充。OOP專心負責核心業務,AOP負責其它雜七雜八的業務。

OOP好比是經理,AOP好比是助理。原先所有事兒,什麼批文件、見客戶、通知下級來開會、向下級傳達指示,所有事兒都是自己做,很繁瑣,搞得精疲力竭,還容易出問題。

現在招了助理AOP,總經理OOP可以專心處理核心的業務,批示下文件、見見客戶就行了。傳遞指示、通知下級開會,這些事兒助理AOP來做。分工明確,效率

高很多。

 

 

這些操作往往可以被多個類使用的,所以叫做一個切麵(Aspect)。

 

目前最流行的AOP框架有2個:Spring  AOP和AspectJ。

 

 

 

 

Spring  AOP

在Spring AOP中,spring是通過代理(proxy)實現的AOP。有2種代理方式:JDK動態代理、CGLIB代理。

 

JDK動態代理

1、新建包jdk_proxy,用來寫代理類、被代理類。包下新建UserInterface介面

1 public interface UserInterface {
2     public void addUser();
3     public void alterUser();
4     public void deleteUser();
5 }

 

 

包下新建一個實現類User

 1 public class User implements UserInterface {
 2     @Override
 3     public void addUser() {
 4         //模擬添加用戶
 5         System.out.println("正在添加用戶");
 6         System.out.println("添加用戶成功");
 7     }
 8 
 9     @Override
10     public void alterUser() {
11         //模擬修改用戶信息
12         System.out.println("正在修改用戶信息");
13         System.out.println("修改用戶信息成功");
14     }
15 
16     @Override
17     public void deleteUser() {
18         //模擬刪除用戶
19         System.out.println("正在刪除用戶");
20         System.out.println("刪除用戶成功");
21     }
22 }

 

這些是要被代理的類。

 

 

2、新建包aspect,用來寫切麵中要使用方法(類)。包下新建類MyAspect

 1 public class MyAspect {
 2     //模擬檢查許可權
 3     public boolean checkPermission(){
 4         System.out.println("正在檢查許可權");
 5         System.out.println("許可權已夠");
 6         return true;
 7     }
 8 
 9     //模擬日誌
10     public void log(){
11         System.out.println("正在寫入日誌");
12         System.out.println("xxx時間,xxx進行xxx操作,操作結果:xxx");
13         System.out.println("日誌寫入完畢");
14     }
15 }

 

 

 

3、在jdk_proxy包下,新建JdkProxy類,要實現InvocationHandler介面(只有invoke()方法)

 1 public class JdkProxy implements InvocationHandler {
 2     //聲明目標介面的實例
 3     private UserInterface user;
 4     
 5     //創建代理方法,參數是目標介面的實例
 6     public Object createProxy(UserInterface user){
 7         this.user=user;   //初始化目標介面實例
 8 
 9         ClassLoader classLoader=JdkProxy.class.getClassLoader();  //獲取當前類的類載入器,當前類類名.class.getClassLoader()
10         Class[] classArr=user.getClass().getInterfaces();  //獲取目標介面實例實現的全部介面
11 
12         //參數:當前類的類載入器,目標介面實例實現的所有介面,當前類的實例
13         return Proxy.newProxyInstance(classLoader,classArr,this);
14     }
15 
16     @Override
17     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18         //聲明切麵
19         MyAspect myAspect=new MyAspect();
20 
21         //前增強,執行切麵中的方法,在執行目標類中的方法之前做一些操作,比如檢查許可權。根據需要選用。
22         myAspect.checkPermission();
23 
24         //執行目標類中的方法。比如addUser()。第一個參數目標對象,第二個是固定的
25         Object object=method.invoke(user,args);
26 
27         //後增強。執行切麵中的方法,在執行目標類中的方法之後做一些操作,比如記錄日誌。根據需要選用。
28         myAspect.log();
29 
30         return object;
31     }
32 }

 

這是代理類,用來代理User類/UserInterface介面。

 

 

4、 新建一個test包,用來寫測試類。包下新建類Test

 1 public class Test {
 2     public static void main(String[] args) {
 3         //JdkProxy的實例
 4         JdkProxy jdkProxy=new JdkProxy();
 5 
 6         //創建目標對象
 7         UserInterface user=new User();
 8 
 9         //通過JdkProxy類的實例動態創建user的代理,因為返回值是Object,需要強制類型轉換,必須用目標介面轉換,不能用實現類轉換
10         UserInterface userProxy=(UserInterface) jdkProxy.createProxy(user);
11 
12         //通過代理調用方法,會自動調用OOP、AOP中的相關方法。
13         userProxy.addUser();
14     }
15 }

 

 

5、運行,看到控制台輸出如下

正在檢查許可權
許可權已夠
正在添加用戶
添加用戶成功
正在寫入日誌
xxx時間,xxx進行xxx操作,操作結果:xxx
日誌寫入完畢

已自動調用AOP(前增強+後增強)、OOP(業務本身)中的方法。

 

 

 

模型分析

 

 

AOP術語

  • Aspect(切麵):用來寫AOP中要用的方法,比如上例中的MyAspect類。
  • Pointcut(切入點):AOP、OOP交匯處,比如addUser()、alterUser()、deleteUser(),這三個方法是OOP中的方法,但使用時還會調用AOP中檢查許可權、記錄日誌的方法,這三個方法就是AOP切入OOP的切入點。
  • Joinpoint(連接點):即切入點+AOP處理的點,比如checkPermission()、addUser()、log()就是三個連接點。
  • Advice(通知/增強):英文意為建議,即做一些其他操作。比如前增強checkPermission()、後增強log()
  • Target  Object(目標對象):被代理的對象,比如UserInterface介面/User類的實例
  • Proxy(代理):即上例的userProxy
  • Weaving(織入):將AOP植入到OOP中,比如上例的JdkProxy類。

 

 

 

 

CGLIB代理

因為JDK動態代理的JdkProxy類中的createProxy()方法中 Class[] classArr=user.getClass().getInterfaces(); //獲取目標介面實例實現的全部介面 ,要用到目標對象的所實現的全部介面,就是說被代理的OOP的核心業務類必須要實現介面。

如果被代理的類沒有實現介面,則可以使用CGLIB代理。

 

1、新建一個cglib包,用來寫代理類、被代理類。包下新建User類(被代理類),不必實現介面

 1 public class User{
 2     public void addUser() {
 3         //模擬添加用戶
 4         System.out.println("正在添加用戶");
 5         System.out.println("添加用戶成功");
 6     }
 7 
 8     public void alterUser() {
 9         //模擬修改用戶信息
10         System.out.println("正在修改用戶信息");
11         System.out.println("修改用戶信息成功");
12     }
13 
14     public void deleteUser() {
15         //模擬刪除用戶
16         System.out.println("正在刪除用戶");
17         System.out.println("刪除用戶成功");
18     }
19 }

 

 

 

2、新建包aspect,包下新建切麵類MyAspect

 1 public class MyAspect {
 2     //模擬檢查許可權
 3     public boolean checkPermission(){
 4         System.out.println("正在檢查許可權");
 5         System.out.println("許可權已夠");
 6         return true;
 7     }
 8 
 9     //模擬日誌
10     public void log(){
11         System.out.println("正在寫入日誌");
12         System.out.println("xxx時間,xxx進行xxx操作,操作結果:xxx");
13         System.out.println("日誌寫入完畢");
14     }
15 }

 

 

 

3、在cglib包下新建CglibProxy類(代理類),需實現MethodInterceptor介面(只有intercept()方法)。註意是org.springframework.cglib.proxy.MethodInterceptor介面,不是其他包下的MethodInterceptor介面。

 1 public class CglibProxy implements MethodInterceptor {
 2     //創建代理,參數是Object類型
 3     public Object createProxy(Object target){
 4         Enhancer enhancer=new Enhancer();   //創建一個動態類對象
 5         enhancer.setSuperclass(target.getClass());  //將這個動態類對象的父類/基類設置為目標類(需要增強的類)
 6         enhancer.setCallback(this);  //設置回調
 7         return  enhancer.create();  //返回創建的代理
 8     }
 9 
10     @Override
11     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
12         //創建切麵實例
13         MyAspect myAspect=new MyAspect();
14 
15         //前增強
16         myAspect.checkPermission();
17 
18         //執行目標方法,參數:形參表的第一個參數、第三個參數
19         Object object=methodProxy.invokeSuper(o,objects);
20 
21         //後增強
22         myAspect.log();
23 
24         //返回代理對象
25         return object;
26     }
27 }

 

 

 

4、新建包test,包下新建測試類Test

 1 public class Test {
 2     public static void main(String[] args) {
 3         //創建CglibProxy的實例
 4         CglibProxy cglibProxy=new CglibProxy();
 5 
 6         //創建目標對象
 7         User user=new User();
 8 
 9         //通過CglibProxy類的實例創建user的代理,因為返回值是Object,需要強制類型轉換,
10         User userProxy=(User)cglibProxy.createProxy(user);
11 
12         //通過代理調用方法,會自動調用OOP、AOP中的相關方法。
13         userProxy.addUser();
14     }
15 }

 

 

 

5、運行,控制台輸出如下

正在檢查許可權
許可權已夠
正在添加用戶
添加用戶成功
正在寫入日誌
xxx時間,xxx進行xxx操作,操作結果:xxx
日誌寫入完畢

 

 

 

說明

  • JDK動態代理需要目標類(被代理的類)實現介面,CGLIB代理不需要目標類實現介面。
  • 需要spring-aop.jar的支持(Spring自帶的)。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ​ 1.python的歷史 python2和python3的區別 python2 源碼不統一,重覆代碼 python 源碼統一,沒有重覆代碼 2004 Django框架的誕生 2.python是編程語言 3.python的種類 4.變數 變數定義的規則: 一個變數名在記憶體中只有一個。 5.常量 變數 ...
  • 一、Redis集群簡介 1、RedisCluster概念 Redis的分散式解決方案,在3.0版本後推出的方案,有效地解決了Redis分散式的需求,當一個服務宕機可以快速的切換到另外一個服務。redis cluster主要是針對海量數據+高併發+高可用的場景。 二、與SpringBoot2.0整合 ...
  • 下載地址 ...
  • 提交leetcode的時候遇到了問題,一直說訪問越界,但仔仔細細檢查n多遍,就是檢查不出來。 因為我用到了count全局變數,自加一來表明當前數組訪問的位置, 後來突然想到,是不是在運行的時候沒有對這個全局變數清零…… 果然,清零之後就可以了……已經3:47了,這裡先上代碼,明天再詳細說吧…… ch ...
  • 1.什麼是Redis? Redis(Remote Dictionary Server)遠程字典伺服器。 是完全開源免費的,用C語言編寫的,遵守BSD協議,是一個高性能的(key/value)分散式記憶體資料庫,基於記憶體運行並支持持久化的NoSql資料庫,是當前最熱門的NoSql資料庫之一,也被人們稱為 ...
  • 最近公司需要開發一個公司內部使用的快遞下單系統,給我的開發任務中有一個生成電子面單功能,為了下單時更方便,利用此功能使用快遞公司給我們的印表機直接列印出電子面單,剛接到這個任務時我想這應該很簡單,不就是做一個表格列印出來嗎,原本以為使用excel或者word等工具直接生成一個文檔,後來經理說不用ex ...
  • 0x00 問題重現 VS COde 打開 .go 文件會自動安裝插件,但是出現了一些工具的下載失敗。 換上全局代理也無法下載。 找了許多教程,但可能由於一些版本的問題,目錄已經變更了,導致吾卡在這裡許久。尤其是 github.com/stamblerre/gocode 。 0x01 解決 MacOS ...
  • 一、前言 眾所周知,spring最核心的兩個功能是aop和ioc,即面向切麵和控制反轉。本文會講一講SpringBoot如何使用AOP實現面向切麵的過程原理。 二、何為aop ​ aop全稱 ,面向切麵,AOP主要實現的目的是針對業務處理過程中的切麵進行提取,它所面對的是處理過程中的某個步驟或階段, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...