日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试

發布時間:2023/12/19 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Java的靜態代理
  • 靜態代理的優缺點
  • ABAP的靜態代理
  • Spring AOP的動態代理
  • JDK動態代理的優缺點
  • CGLIB動態代理的優缺點
  • ABAP CGLIB的模擬實現
  • ABAP Pre和Post Exit

Jerry之前一篇文章 SAP產品增強技術回顧,提到基于Java編程語言實現的SAP Commerce,借助Spring框架的支持,能使用面向切面編程的理念(Aspect Orient Programming,以下簡稱AOP),將業務代碼和非業務代碼(比如權限檢查,日志記錄,性能統計等)徹底分離開。

下圖是某應用里方法的常規實現:權限檢查,日志記錄和性能檢測的代碼一次又一次地侵入到本應只包含業務代碼的三個方法中:

下圖是應用AOP之后的方法實現:三個方法體內只包含純粹的業務代碼,看起來清爽了很多。權限檢查,日志記錄和性能檢測的代碼,作為仍需關注的三個方面,以切面的方式編織到三個方法中。Weave,AOP里的術語,中文材料里經常譯成“編織”,描述了被代理類的方法通過非源代碼修改層面被增添以新邏輯的動作。

我們說面向對象編程(Object Oriented Programming,簡稱OOP)是一種理念,不同的編程語言可以有不同的實現。同理,AOP這種理念,不同的編程語言也存在不同的實現。

Java AOP的實現可以分為靜態代理和動態代理兩種。無論哪種代理方式,一言以蔽之,AOP的核心為,業務邏輯位于原始類中始終保持不變,而編織的非業務邏輯位于代理類中。運行時執行的代碼,實際上被調用的是代理類,原始類的業務邏輯通過代理類被間接地調用。

代理模式的UML圖:

業務邏輯在編譯期間被編織進入代理類的方式,稱為靜態代理;業務邏輯在運行期間才進行編織的方式,稱為動態代理。準確地說,編譯期編織還可細分為編譯時和編譯后編織,而運行期間編織又可細分為載入時編織和運行時編織,但這種細分方式不影響本文接下來的闡述,所以后續仍只按照編譯期和運行期兩大類來介紹。

看一些具體的例子。

Java靜態代理

定義一個IDeveloper的接口,里面包含一個writeCode的方法。創建一個Developer類,實現該方法。

測試:創建一個名為Jerry的Developer實例,調用writeCode方法。

假設我想讓Developer在寫代碼之前,先編寫對應的文檔,但我不想把寫文檔這個邏輯,侵入到writeCode方法里。這里“編寫文檔”,就相當于待編織的非業務邏輯,或者叫做待編織的切面邏輯。

使用靜態代理的思路,另外新建一個代理類DeveloperProxy:

注意上圖的writeCode方法,首先第8行完成文檔編寫的任務,然后代理類在第9行調用被代理類Developer的writeCode方法,完成寫代碼的實際業務邏輯。

測試代碼:

Developer和DeveloperProxy都實現了同一個接口IDeveloper,對于消費者代碼來說,它完全感知不到也不必要去感知這兩個接口實現類的內部差異——這一切對消費者代碼來說完全透明。消費者拿到的引入,指向的是類型為IDeveloper接口的變量,然后調用定義在接口上的writeCode方法即可。

靜態代理的優缺點

從以上例子可以看出,靜態代理工作的基石是接口,如果原始類由于某種原因,無法改造成為某個接口的實現類(比如原始類來自系統遺留代碼,無法重構),則靜態代理這條路行不通。

針對每個原始類,采用靜態代理,都需要創建一個具有持久存儲的代理類。這種方式便于理解,并且非業務邏輯(前例中的“寫文檔”行為)在編譯期間植入靜態代理類,實際運行時性能優于即將介紹的動態代理。

在Java里如果不想手動創建靜態代理類,可以使用工具AspectJ來自動完成。由于本文的讀者主要是ABAP開發人員,這里略過其使用方式。

ABAP靜態代理類的自動創建

我仿照Java AspectJ的思路,用ABAP寫了一個類似的原型。下面是使用方法。

首先我創建一個類CL_HELLOWORLD:

我想自動為該類創建一個靜態代理,在代理類的PRINT方法里,除了調用這個原始類的PRINT方法外,再做一些額外的邏輯,比如打印一些輸出。

調用下圖的GET_PROXY方法,將自動為CL_HELLOWORLD創建一個靜態代理類,將第7行和第8行指定的額外邏輯編織到靜態代理類的PRINT方法里:

測試:調用靜態代理類的PRINT方法,得到下圖的輸出,能觀察到編織到靜態代理類的兩行WRITE語句,分別在原始類PRINT方法之前和之后被調用了:

SE24可以觀察到,通過我寫的工具自動創建的ABAP靜態類,及編織到代理類方法PRINT里的額外邏輯:


這個工具的核心是調用ABAP Class API生成新的ABAP類,源代碼可以在文末Jerry提供的鏈接里獲得:

Spring AOP的動態代理

所謂動態代理,即AOP框架在編譯期不會對原始類做任何處理,而是直到應用運行期間,在內存中臨時為需要被代理的類生成一個AOP對象,該對象包含了原始類的全部方法,并且在被代理的方法處做了增強處理,編織入新的邏輯,并回調原始類的方法。

Spring AOP動態代理有兩種實現方式:JDK動態代理和CGLIB動態代理。

JDK動態代理

JDK動態代理的原理是基于Java反射機制實現的方法攔截器機制。

我們在第一個例子的基礎上,增添一個新的ITester接口,代表測試人員這個崗位:

現在的需求是給測試人員的doTesting方法內也植入編寫文檔的邏輯。如果采用靜態代理的方式,我們得又創建一個TesterProxy的靜態代理類。隨著開發小組里人員崗位類型的增加,這些靜態代理類的個數也隨之增加。

那么用動態代理如何優雅地避免這個問題呢?

創建一個新的代理類,取名為EnginnerProxy,名字暗示了這個實現了JDK標準接口InnovationHandler的類,在運行時能統一代理一個軟件開發團隊里所有角色的工程師類的方法。

第七行的bind方法,接收一個被代理類的實例,在運行時動態為該實例創建一個臨時的代理類實例。所謂臨時,指該代理實例的生命周期只存在于當前會話中,應用運行結束后即銷毀,不會像靜態代理類那樣會持久化存儲。

運行時代理類的方法一旦執行,無論是Developer的writeCode, 還是Tester的doTesting方法,均會被EnginnerProxy的invoke方法攔截,在invoke方法內統一執行第17行的文檔撰寫邏輯,然后再調用18行包含了業務邏輯的原始類方法。

下圖是測試代碼及運行結果,現在無論是Developer還是Tester,在寫代碼和做測試之前,都會自動執行文檔撰寫的任務了:

基于JDK動態代理的優缺點

顯而易見,在需要代理多個類時,動態代理只需創建一個統一的代理類,而不必像靜態代理那樣,需要為每個包含業務邏輯的類單獨創建代理類。而代理類“用后即焚”,也避免了在工程文件夾里生成太多代理類。

另一方面,因為動態代理在運行時通過Java反射機制實現,運行時的性能劣于在編譯期間進行代理邏輯編織的靜態代理。此外,JDK動態代理工作的前提條件同靜態代理一樣,也需要被代理的類實現某個接口。

看個反例,假設產品經理類ProductOwner未實現任何接口:

使用JDK動態代理,在運行時會拋ClassCastException異常:

正因為JDK動態代理的這種局限性,存在另一種動態代理的實現方式:基于CGLIB的動態代理。

CGLIB(Code Generation Library)是一個Java字節碼生成庫,可以在運行時對Java類的字節碼進行處理和增強,底層基于字節碼處理框架ASM實現。

基于CGLIB的動態代理可以繞過JDK動態代理的限制,即使一個需要被代理的類沒有實現任何接口,也能使用CGLIB動態代理。

注意這次使用CGLIB創建的統一代理類,導入的開發包來自net.sf.cglib.proxy, 而非JDK動態代理解決方案中的java.lang.reflect:

消費代碼的風格同JDK動態代理類似:

CGLIB動態代理的優缺點

CGLIB克服了JDK動態代理需要被代理類必須實現某個接口才能工作的限制,然而其本身也有局限性。CGLIB本質上是運行時用API操作Java類的字節碼的方式,直接創建一個繼承自被代理類的子類,然后將切面邏輯編織到這個子類方法中去。顯而易見,如果被代理類被定義成無法繼承,比如被Java和ABAP里的final關鍵字修飾,則CGLIB動態代理這種方式也無法工作。

做一個測試,我將ProductOwner類標志為final,即無法被繼承,這時在運行之前的測試代碼,會遇到異常和錯誤消息:Cannot subclass final class

ABAP動態代理

因為ABAP無法在語言層面精確做到像Java JDK InnovationHandler那樣能夠用一個代理類統一攔截多個被代理類方法執行的效果,因此Jerry選擇對另一種動態代理,即CGLIB代理方式,用ABAP進行模擬。

首先創建一個需要被代理的類,業務邏輯寫在GREET方法里。

接著使用Jerry自己實現的ABAP CGLIB工具類,通過其方法GET_PPROXY得到這個類的代理類,并調用代理類的GREET方法:

上圖第8行和第9行是包含了兩個切面邏輯的類,我期望其方法分別在被代理類的GREET調用之前和調用之后被執行。

ABAP CGLIB的核心在GET_PROXY方法里的generate_proxy方法內:

這里使用了ABAP動態生成類的關鍵字GENERATE SUBROUTINE POOL, 根據內表mt_source里包含的預先拼湊好的源代碼,生成新的臨時類。這個類不會在SE24或者SE80里存儲,僅僅存活在當前應用的會話里。

第17行動態生成新的代理類之后,第21行生成一個該代理類的實例,然后在第23和26行分別植入切面邏輯。

最后調用這個代理類實例的GREET方法,打印輸出如下:

其中Hello World是原始被代理類即ZCL_JAVA_CGLIB的GREET方法的輸出,而它的前后兩行為調用ABAP CGLIB生成代理類時傳入的切面邏輯。

到目前為止,盡管我們意識到靜態代理和動態代理都各自存在一些缺陷,但從這些缺陷出現的原因,也再次提醒我們,在編寫新的代碼時,要盡量面向接口編程,盡量避免直接面向實現編程,從而降低程序的耦合性,提高應用的可維護性,可復用性和可擴展性。

以上介紹的ABAP CGLIB工具只是Jerry開發的一個原型,在ABAP里如果僅僅想將切面邏輯(比如權限檢查,日志記錄,性能分析)徹底地同業務邏輯隔離開,可以使用ABAP Netweaver提供的對類方法增強的標準方式:Pre-Exit和Post-Exit.

選中要增強的類,點擊Enhance菜單:

這種增強和被代理的類是分開存儲的:

創建新的Pre-Exit:

點擊Pre-Exit的面板,就可以進去編寫代碼了:

在運行時,被代理類ZCL_JAVA_CGLIB的GREET方法執行之前,Pre-Exit里的代碼會自動觸發:

Jerry之前在SAP Business By Design這個產品工作的時候,在不修改產品標準代碼的前提下,用這種Exit技術實現了很多的客戶需求。典型的客戶需求是,在SAP標準UI增添擴展字段,其值通過后臺復雜的邏輯計算出來。于是我們首先把后臺API的Response結構體做增強,新建一個擴展字段;然后給后臺API取數方法創建一個Post-Exit,將擴展字段的填充邏輯實現在Exit里。

采用Pre和Post-Exit,雖然使用方式上和Java Spring AOP基于注解(Annotation)的工作方式相比有所差異,但從效果上看,也能實現Spring AOP將業務邏輯和非業務邏輯嚴格分開的需求。

本文介紹的Java和ABAP的靜態和動態代理,以及ABAP模擬Java CGLIB的實現,在Jerry發布的SAP社區博客上有詳細敘述:

  • Implement CGLIB in ABAP

  • Create dynamic proxy persistently in Java and ABAP

  • Various Proxy Design Pattern implementation variants in Java, ABAP and JavaScript

本文提到的Jerry開發的所有ABAP原型和工具,在這個鏈接里有源代碼。

今后如果有人聊到關于ABAP能否進行面向切面編程的話題,您或許可以提到Jerry這篇文章。感謝閱讀。

要獲取更多Jerry的原創文章,請關注公眾號"汪子熙":

ABAP專題

  • Jerry的ABAP, Java和JavaScript亂燉

  • ABAP開發人員未來應該學些什么

  • Jerry 2017年的五一小長假:8種經典排序算法的ABAP實現

  • Jerry的ABAP原創技術文章合集

  • 300行ABAP代碼實現一個最簡單的區塊鏈原型

  • 使用Java+SAP云平臺+SAP Cloud Connector調用ABAP On-Premise系統里的函數

  • 在SAP云平臺的CloudFoundry環境下消費ABAP On-Premise OData服務

  • ABAP vs Java, 蛙泳 vs 自由泳

  • 聊聊C語言和ABAP

  • 動手使用ABAP Channel開發一些小工具,提升日常工作效率

  • 我用ABAP做過的那些無聊的事情

  • 不喜歡SAP GUI?那試試用Eclipse進行ABAP開發吧

  • 使用Visual Studio Code編寫和激活ABAP代碼

  • 你的ABAP程序給佛祖開過光么?來試試Jerry這個小技巧

  • 在SAP云平臺ABAP編程環境上編寫第一段ABAP程序

  • SAP官方發布的ABAP編程規范

  • ABAP Code Inspector那些隱藏的功能,您都知道嗎?

  • 還在用ABAP進行SAP產品的二次開發?來了解下這種全新的二次開發理念吧

  • ABAP Netweaver體內的那些寄生式編程語言

  • 從SAP社區上的一篇博客開始,聊聊SAP產品命名背后的那份情懷

  • 云端的ABAP Restful服務開發

  • 如何在SAP云平臺ABAP編程環境里把CDS view暴露成OData服務

  • 使用abapGit在ABAP On-Premises系統和SAP云平臺ABAP環境之間進行代碼傳輸

  • 30分鐘用Restful ABAP Programming模型開發一個支持增刪改查的Fiori應用

  • Jerry帶您了解Restful ABAP Programming模型系列之二:Action和Validation的實現

  • Jerry帶您了解Restful ABAP Programming模型系列之三:云端ABAP應用調試

  • SAP云平臺上的ABAP編程環境里如何消費第三方服務

  • ABAP開發者上云的時候到了 - 現在大家可以免費使用SAP云平臺ABAP環境的試用版了

  • 學而不思則罔 - SAP云平臺ABAP編程環境的由來和適用場景

  • SAP云平臺里的三叉戟應用

  • 如何基于Restful ABAP Programming模型開發并部署一個支持增刪改查的Fiori應用

  • SAP 2019 TechEd Key Note解讀:云時代下SAP從業人員如何做二次開發?

  • 有哪些ABAP關鍵字和語法,到了ABAP云環境上就沒辦法用了?

  • ABAP開發環境終于支持以駝峰命名法自動格式化ABAP變量名了

  • 利用ABAP 740的新關鍵字REDUCE完成一個實際工作任務

  • 一段讓人瑟瑟發抖的ABAP代碼

  • 昨日萬圣節ABAP怪獸級代碼謎團,公布答案啦

  • 介紹一種在ABAP內核態進行內表高效拷貝的方法

  • 使用SAP Cloud Application Programming模型開發OData的一個實際例子

  • 當ABAP遇見普羅米修斯

  • 使用ABAP繪制可伸縮矢量圖

  • ABAP開發環境語法高亮的那些事兒

  • SAP錯誤消息調試之七種武器:讓所有的錯誤消息都能被定位

  • 使用ABAP操作Excel的幾種方法

  • SAP GUI里的收藏夾事務碼管理工具

  • SAP GUI和Windows注冊表

  • 有了Debug權限就能干壞事?小心了,你的一舉一動盡在系統監控中

  • ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX這些東東是什么鬼

  • 實現ABAP條件斷點的三種方式

  • 使用SAT跟蹤監控從瀏覽器打開的SAP應用的性能和調用棧

  • 一個13年ABAP老兵的建議:了解這些基礎知識,對ABAP開發有百利而無一害

  • SAP ABAP Netweaver容器化, 不可能完成的任務嗎?

  • SAP產品增強技術回顧

  • SAP API開發方法大全

總結

以上是生活随笔為你收集整理的浅谈Java和SAP ABAP的静态代理和动态代理,以及ABAP面向切面编程的尝试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。