什么是代理?
引入
假设有一个转账方法pay(String a,String b,double money),意为a向b转账了一笔钱。
然后写一个Test类来调用这个方法:
这样确实能够调用pay方法来进行金额转移,但是如果a和b并不合法,而且a账户中的money不够呢?
所以我们需要在调用之前对其进行校验:

校验固然可以写在pay方法当中,但是这样体现不了pay方法的核心功能。校验也可以写在pay所在的类中,但是这样的话pay所在的类就给我们提供了很多重要的方法(验证a、验证b以及验证金额),如果后续要在原有的逻辑上增加新的功能,修改会比较困难。Java提供的代理模式可以很好解决这个问题。
代理模式可以增强原有的逻辑功能。
代理模式概念
给目标提供一个代理对象,并且由代理对象控制对目标对象的引用。
接着上面的例子:

转账对象为目标对象,用户在调用过程中是看不到目标对象的,代理对象控制着目标对象的引用。
代码示例
//目标类
public class pay {
private void payMoney(String a,String b,double money) {
System.out.println(a+"向"+b+"转账了"+money+"元");//模拟转账过程
}
}
//代理类
public class ZFSoftWare {
pay pay=new pay(); //创建pay对象,控制对其的引用
}
//测试类
public class Test {
ZFSoftWare zfSoftWare=new ZFSoftWare();
}
这样用户在调用代理对象时,目标对象也被创建好了。但是此时用户是无法调用到pay方法的,这时我们在代理类新增调用pay的方法:
public class ZFSoftWare {
pay pay=new pay(); //创建pay对象,控制对其的引用
public void ProxyPay(String a,String b,double money) {
pay.payMoney(a, b, money);
}
}
这样就可以调用了。但是为什么要多使用一个代理类来套着调用呢?这就涉及到代理模式的核心功能:控制着对目标对象的引用。这时我们也可以在代理类中添加其他逻辑(比如校验),也就增强了原有的逻辑和功能。
//目标类
public class pay {
public void payMoney(String a,String b,double money) {
System.out.println(a+"向"+b+"转账了"+money+"元");//模拟转账过程
}
}
//这是一个代理类
public class ZFSoftWare {
pay pay=new pay(); //创建pay对象,控制对其的引用
public void ProxyPay(String a,String b,double money) {
pay.payMoney(a, b, money);
}
public void checkA(String a) {
System.out.println("模拟对a的验证");
}
public void checkB(String b) {
System.out.println("模拟对b的验证");
}
public void checkMoney(double money) {
System.out.println("模拟对money的验证");
}
}
//测试类(用户)
public class Test {
public static void main(String[] args) {
ZFSoftWare zfSoftWare=new ZFSoftWare();
zfSoftWare.checkA("a");
zfSoftWare.checkB("b");
zfSoftWare.checkMoney(10.0);
zfSoftWare.ProxyPay("a","b",10.0);
}
}
运行结果:

代理的分类
分为静态代理和动态代理。
静态代理
上述例子就是一个静态代理的例子。
动态代理
动态代理有两种实现,一种是基于JDK的实现,一种是cglib。这里我们主要看jdk实现:
动态代理对上述例子的实现:
//这是两个目标类
public class Scan implements InterScan{
public void scan() {
System.out.println("扫描二维码");//模拟扫描二维码过程
}
}
public class pay implements InterPay{
public void payMoney(String a,String b,double money) {
System.out.println(a+"向"+b+"转账了"+money+"元");//模拟转账过程
}
}
//这是两个代理接口
public interface InterPay {
public void payMoney(String a,String b,double money);
}
public interface InterScan {
public void scan();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这是一个代理类
public class ZFSoftWare implements InvocationHandler{
private Object o;//第一步:实现对目标类的引用
public ZFSoftWare(Object o) {
this.o=o;
}
public void checkA(String a) {
System.out.println("模拟对a的验证");
}
public void checkB(String b) {
System.out.println("模拟对b的验证");
}
public void checkMoney(double money) {
System.out.println("模拟对money的验证");
}
//第二步:知道目标类的核心方法
//o.getClass().getClassLoader()获取目标类的构造器
//o.getClass().getInterfaces()获取目标类接口
public Object aa() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
}
//Object proxy:jdk创建的代理类,无需赋值
//Method:目标类中的方法,jdk提供,无需赋值
//Object[]:目标类中的方法参数,jdk提供,无需赋值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(o,args);
return null;
}
}
//这是测试类
public class Test {
public static void main(String[] args) {
InterPay zf1=(InterPay) new ZFSoftWare(new pay()).aa();
zf1.payMoney("a", "b", 100.0);
InterScan zf2=(InterScan) new ZFSoftWare(new Scan()).aa();
zf2.scan();
}
}
Scan和pay是两个目标类,分别实现了 InterScan和InterPay接口。Scan类中的Scan()方法模拟了扫描二维码的过程,pay类中的payMoney()方法模拟了转账过程;InterPay和 InterScan是两个代理接口,分别定义了payMoney()和Scan()方法。
ZFSoftWare一个代理类,实现了InvocationHandler接口。它通过动态代理的方式对目标类的方法进行增强。
Test类是测试类,通过ZFSoftWare代理类创建了InterPay和InterScan的代理对象,并调用了相应的方法。
执行流程
-
在Test类中,通过ZFSoftWare代理类创建了InterPay和InterScan的代理对象。
-
调用zf1.payMoney("a","b",100.0)时ZFSoftWare的invoke()方法被触发,执行了pay类的 payMoney()方法。 -
调用zf2.scan()时,ZFSoftWare的 invoke()方法被触发,执行了 Scan类的scan()方法。
3万+

被折叠的 条评论
为什么被折叠?



