作者TKB5566 (= =)
看板java
標題[語法] 代理人設計模式
時間Mon Dec 11 21:01:24 2023
最近在研讀Spring AOP,而AOP使用了代理人設計模式,要理解何謂AOP就必須先理解
何謂代理人設計模式,因此我嘗試整理了該設計模式的大綱:
代理人模式從表面上的語法來看,類似在Java IO看到的裝飾者模式,
兩者都是透過包裝某個既有的類別,去增加既有類別的功能。
但是代理人設計模式包裝某類別的目的,是出於增加與業務邏輯無關,額外的功能。
而裝飾者模式的目的是,增加與業務邏輯有關的功能。例如Java IO就是透過裝飾者模式
不斷對物件加強其存取檔案的功能。
代理人模式要如何做到這個目的呢?
就是新增/宣告一種代理類別,將某個包含業務邏輯的物件封裝起來,
這樣該代理類別內,就有一區塊是用於封裝業務邏輯物件;然後於封裝以外的範圍,
去給代理類別增加功能。這樣這個代理類別包含了業務邏輯、又有了額外的功能。
所以就實作了代理人模式。
若某物件的業務邏輯已經定型,不須做額外改變,因此不該隨便去動到該物件時,
透過代理類別去封裝該物件,可避免外部其他物件直接存取到該業務邏輯物件,
外部物件只能存取代理類別new出來的代理物件。這樣可以確保程式的安全性。
------------------------------------
而代理人模式又分為靜態代理與動態代理。
靜態代理是直接由程式撰寫者設定代理類別要去代理的物件,
一代理類別對應一被代理物件,那麼多個代理類別,就會去對應多個被代理物件。
這樣實作代理人模式的優點,就是直接把代理規則寫得清清楚楚,因此程式有易讀性。
而
動態代理,是不直接對代理類別,指定其要去代理的物件,而是於程式執行過程中
才去動態的決定代理類別要去代理的物件是什麼。
這樣設計的好處是,一個代理類別可以動態的去根據狀況,去代理多個不同的物件,
也就是說程式會變得更靈活;
而
動態代理,只要一個代理類別可代理多個代理物件,
比起靜態代理是
「一代理類別只能對應一被代理物件,多個代理類別,去對應多個被代理物件」。
的情形,顯然動態代理可以省下更多的程式碼。
1
要實作動態代理的類別,要去封裝業務邏輯物件;故動態代理類
需要吃一個業務邏輯型別之物件作為參數。
這時還不知道該業務邏輯物件是什麼,當然也就不知道她的型別,故這時候
業務邏輯物件的型別只能是Object,
2
接著實作invocationHandler介面的invoke方法,所以
動態代理的類別,要implements invocationHandler。
該方法要透過反射的語法,設定要該業務邏輯/要代理的物件是什麼?
2-1
具體作法是呼叫method.invoke(),並將被代理物件的reference作為參數傳入。
這樣該動態代理類即具備了被代理物件之方法、功能。
2-2
並可於method.invoke()前後,添加切面程式。
3
這樣即完成代理物件的邏輯的設定。
---------------------------------------
當代理類別宣告完成,要去new來使用時,要呼叫proxy類別的newProxyInstance方法
該方法具體要傳入的參數,有
object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
handler
前兩個參數,是生成被代理物件所必須的資訊、第三個參數,是具體生成被代理物件、
封裝被代理物件至代理物件內部之過程;另外第三個參數還有添加切面程式之作用。
前兩個參數是固定的,
第三個參數是描述具體封裝代理物件的邏輯,讓java去實際做出代理物件。
才能使用該代理物件。
接著要注意的是,
若被代理物件,一開始是實作某個介面的話,那麼代理物件的型別,
就應該是該介面之型別,因為代理物件也是實作了該介面所定義的方法。
除非被代理物件並沒有實作任何類別,這樣的話代理物件的型別,
才會是被代理物件之型別。
----------------------------------------
聽起來很複雜,但是Spring AOP透過聲明式的語法,大幅度降低了動態代理的難度。
至於要具體如何透過Spring AOP來做到代理人模式?
1
首先,需要在Bean註冊檔,添加一段設定,用來告訴Spring將使用Spring AOP來協助生成
代理物件。
2
接著,宣告一Component,該Component要用來實作切面程式,而要定義這個Component
為切面程式,需要於該類別開頭,添加@Aspect這個註釋。
3
接著,實作該類別的切面程式;
3-1
這要透過@Pointcut來定義要被切面的業務邏輯類/方法。
3-2
再來透過前置、後置、後置回傳、例外、環繞切面註釋,搭配對應要執行的方法,
決定具體要在哪裡執行切面,以添加額外的邏輯。
3-3
切面註釋有好幾個,但最好用的切面註釋是環繞註釋;用@Around表示於對應方法開頭。
4
以上設定即可讓Spring AOP去生成被代理物件。而
被代理物件的型別,即為介面型別。
直接執行該被代理物件,代理到的方法,即可同時執行透過Spring AOP添加的額外邏輯。
這就是一個簡易的Spring AOP流程。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 49.216.167.56 (臺灣)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/java/M.1702299686.A.1B4.html
1F:推 xrururururu: 推 12/12 23:23
2F:推 NullLife: Spring有提供兩種代理模式 一是你提到的jdk動態代理 12/13 09:27
3F:→ NullLife: 二是透過CGlib 12/13 09:27
※ 編輯: TKB5566 (111.125.132.31 臺灣), 05/09/2024 20:51:23