Java代理

什么是代理?

引入

        假设有一个转账方法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的代理对象,并调用了相应的方法。


        执行流程

  1. 在Test类中,通过ZFSoftWare代理类创建了InterPay和InterScan的代理对象。

  2. 调用zf1.payMoney("a","b",100.0)时ZFSoftWare的invoke()方法被触发,执行了pay类的 payMoney()方法。

  3. 调用zf2.scan()时,ZFSoftWare的 invoke()方法被触发,执行了 Scan类的scan()方法。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值