作者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/cn.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