[語法] 代理人設計模式

看板java作者 (= =)時間1年前 (2023/12/11 21:01), 7月前編輯推噓2(201)
留言3則, 2人參與, 1年前最新討論串1/1
最近在研讀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://www.ptt.cc/bbs/java/M.1702299686.A.1B4.html

12/12 23:23, 1年前 , 1F
12/12 23:23, 1F

12/13 09:27, 1年前 , 2F
Spring有提供兩種代理模式 一是你提到的jdk動態代理
12/13 09:27, 2F

12/13 09:27, 1年前 , 3F
二是透過CGlib
12/13 09:27, 3F
※ 編輯: TKB5566 (111.125.132.31 臺灣), 05/09/2024 20:51:23
文章代碼(AID): #1bTmWc6q (java)
文章代碼(AID): #1bTmWc6q (java)