深入解析SSH框架——代理模式

代理模式
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。
换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。
客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口。
以生活中的“代理律师”为例来理解“代理模式”。
打官司是件非常麻烦的过程:案件调查取证、查找法律条文、起草法律文书、法庭辩论、签署法律文件、申请法院执行……但打官司的人只关心法宣判结果。此时,打官司的人就可聘请“代理律师”来完成整个打官司的所有事务。当事人只需与代理律师签订了“全权委托协议”,那么整个打官司的过程,当事人均可不出现。
聘请代理律师时以下几点需要特别说明:
(1) 当事人与代理律师是在为同一件事情努力。
(2) 法院所有的具体事务都是通过代理律师完成。
(3) 在法院需要当事人完成某些工作时,代理律师会通知当事人,并为其出谋划策,即增强当事人。
对于代理模式,需要注意以下几点:
(1) 代理类和目标类要实现同一个接口,即业务接口。
(2) 客户类对目标类的调用均是通过代理类完成的。
(3) 代理类的执行既执行了对目标类的增强业务逻辑,又调用了目标类的主业务逻辑。

根据代理关系建立的时间不同,可以将代理分为两类:静态代理与动态代理。就好比当事人与律师之间的关系一样,也分为法律顾问与代理律师两类。
静态代理
概念
静态代理是指,代理类在程序运行前就已经定义好,其与目标类的关系在程序运行前定义代理类 AccountProxy。这个类要实现 IAccount 接口。并且该代理类就已经确立。
静态代理类似于企业与企业的法律顾问间的关系。法律顾问与企业的代理关系,并不是在“官司”发生后才建立的,而是之前就确立好的一种关系。
代理实现与解析
静态代理实现转账: proxy_static
(1)定义业务接口 IAccountService,其中含有抽象方法 transfer()。

(2)定义目标类 AccountServiceImpl,该类实现了业务接口。在对接口方法的实现上,
只实现主业务逻辑转账即可。这个方法称为目标方法。

(3) 定义代理类 AccountProxy。这个类要实现 IAccount 接口。并且该代理类要将接口对象作为一个成员变量,还要定义一个带参的构造器,这个参数为接口对象。目的是,将目标对象引入代理类,以便代理类调用目标类的目标方法。

(4) 定义客户类 Client。在客户类中首先要创建目标对象,再创建代理对象,并使用目标对象对其进行初始化。然后由代理对象来调用执行业务方法。

JDK 动态代理
动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(如代理工厂类)在程序运行时由 JVM 根据反射等机制动态生成的。代理对象与目标对象的代理关系在程序运行时才确立。
对比静态代理,静态代理是指在程序运行前就已经定义好了目标类的代理类。代理类与目标类的代理关系在程序运行之前就确立了。
概念
动态代理类似于普通当事人与聘请的律师间的关系。律师是在“官司”发生后,才由当事人聘请的。即代理关系是在“官司”发生后才确立的。
动态代理的实现方式常用的有两种:使用 JDK 的 Proxy,与通过 CGLIB 生成代理。
通过 JDK 的 java.lang.reflect.Proxy 类实现动态代理 ,会使用其静态方法newProxyInstance(),依据目标对象、业务接口及业务增强逻辑三者,自动生成一个动态代理对象。
public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,
InvocationHandler handler)
loader:目标类的类加载器,通过目标对象的反射可获取
interfaces:目标类实现的接口数组,通过目标对象的反射可获取
handler:业务增强逻辑,需要再定义。
InvocationHandler 是个接口,其具体介绍如下:
实现了 InvocationHandler 接口的类用于加强目标类的主业务逻辑。这个接口中有一个方法 invoke(),具体加强的代码逻辑就是定义在该方法中的。程序调用主业务逻辑时,会自动调用 invoke()方法。
invoke()方法的介绍如下:
public Object invoke ( Object proxy, Method method, Object[] args)
proxy:代表生成的代理对象
method:代表目标方法
args:代表目标方法的参数
由于该方法是由代理对象自动调用的,所以这三个参数的值不用程序员给出。
第二个参数为 Method 类对象,该类有一个方法也叫 invoke(),可以调用目标类的目标方法。这两个invoke()方法,虽然同名,但无关。
public Object invoke ( Object obj, Object... args)
obj:表示目标对象
args:表示目标方法参数,就是其上一层 invoke 方法的第三个参数
该方法的作用是:调用执行 obj 对象所属类的方法,这个方法由其调用者 Method 对象确定。
在代码中,一般的写法为
method.invoke(target, args);
其中,method 为上一层 invoke 方法的第二个参数。这样,即可调用了目标类的目标方法。
代理实现与解析
动态代理实现转账: proxy_dynamic
(1) 定义业务接口IAccounSevice,其中含有抽象方法 transfer()。
(2) 定义目标类 AccountServiceImpl,该类实现了业务接口。在对接口方法的实现上,只实现主业务逻辑。这个方法称为目标方法。
以上两步与静态代理类 staticproxy 中代码相同。
(3) 定义主业务增强逻辑类 MyExtension,该类需实现接口 InvocationHandler。在该类中定义一个 Object 类型的成员变量,还要定义一个带参的构造器,这个参数为 Object 对象。目的是,将目标对象引入该类,以便通过反射调用目标方法。
当然,也可以将这个属性定义为 IAccount 接口类型,但最好不要这样做,最好将其定义为 Object。因为,这样这个主业务增强逻辑可以适用于本项目中的任何类型的目标类, 而不仅仅拘泥于某一个类。

(4) 定义客户类 Client。客户类中主要语句有三句:
A、定义目标对象。在生成代理对象时会需要目标对象对其初始化。
B、定义代理对象。需要注意的是,代理类 Proxy 会通过反射机制,自动实现 IAccount接口。代理对象需要使用目标对象对其进行初始化。
C、代理对象调用主业务方法。

CGLIB 动态代理
概念
使用 JDK 的 Proxy 实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。
但对于无接口的类,要为其创建动态代理,就要使用 CGLIB 来实现。CGLIB 代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB 生成动态代理,要求目标类必须能够被继承,即不能是 final 的类。
CGLIB(Code Generation Library)是一个开源项目,是一个强大的、高性能的、高质量的代码生成类库。它可以在运行期扩展和增强 Java 类。Hibernate 用它来实现持久对象的字节码的动态生成,Spring 用它来实现 AOP 编程。
CGLIB 包的底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码操控框架),来转换字节码并生成新的类。CGLIB 是通过对字节码进行增强来生成代理的。
如果说静态代理是“法律顾问(律师)”,动态代理是“代理律师”,那么 CGLIB 代理则是“老父亲的儿子”。
当事人是打官司的人,而律师也是打相同官司的人。但他们事先有个约定,就是律师只对官司相关的事情进行“增强”。这个约定是通过“接口”来实现的。这种是 JDK 的代理原理。
老父亲是需要被增强的目标类,而儿子则是用于增强老父亲的代理类。不同于当事人与律师关系的是,老父亲与儿子间对于要增强的事情,事先是没有约定的。老父亲需要儿子帮助他做什么事情,即增强哪些方法,事先是没有约定的。老父亲让其增强什么,儿子就需要增强什么。即,他们是不需要“接口”的。

代理实现与解析
使用 CGLIB 创建代理步骤: ---- cglibproxy
Setp1:导入 CGLIB 的 Jar 包: cglib-full.jar。
Step2:定义目标类。注意不用实现任何接口。

Step3:创建代理类的工厂。该类要实现 MethodInterceptor 接口。该类中完成三样工作:

1) 声明目标类的成员变量,并创建以目标类对象为参数的构造器。用于接收目标对
象。

(2) 定义代理的生成方法,用于创建代理对象。方法名是任意的。代理对象即目标 类的子类。

注意,只所以在 setCallback()方法中可以写上 this,是因为 MethodIntecepter 接口继承自 Callback,是其子接口。查看源码:

(3) 定义回调接口方法。对目标类的增强这在这里完成。

intercept()方法中各参数的意义:
proxy:代理对象
metho:代理对象的方法,即增强过的业务方法
args[]:方法参数
methodProxy:代理对象方法的代理对象Step4:创建测试类。

最后奉上视频教程👇,视频观看效果更佳!!走过路过别忘素质三连哦~~

