一.
动态代理指利用反射去获取和调用目标类的方法。
为什么要代理?
如果A类要去调用C类的方法,但是C类拒绝让A类调用,但同意让B类去调用,那么我们的A类就可以通过B类去调用C的方法。 此时的B类就是C类(目标类)的代理对象
通俗来讲就是 我是厂长卖cpu的,如果一个人要来我这里买个cup那我肯定是拒绝的(量小瞧不上=.=),但是可以通过我旗下的代理商购买这款cpu(代理商每次都从我这里进购大量的货)。
此时代理商就扮演了重要的作用。
所谓代理无非就是类似中介,中间人,媒婆等角色。当你想要某种服务的时候 又没办法直接联系提供服务的人的时候,就可以找中介(目标类的代理对象)
二. 代理分静态代理和动态代理。
假如我是制造cpu的大厂,我旗下的代理商有 某bao,某wei,某duo,某yu等。
然后一个cup购买者想要购买cpu,那么他可以通过代理商购买;
静态代理:首先我这个厂C是卖cpu的吧,所以他需要有卖cpu的方法。不妨叫sellCPU();
此时代理商B也是要卖cpu的吧,所以他也同样要有sellCPU() 方法;只不过代理商的sellCPU()方法的内部是通过持有对象A并且调用A的sellCPU(),并且扩展了一些新的功能(比如我加价,在工厂的销售价格上再加钱)
由于代理商和厂家有相同的方法,那么我们可以直接把这个方法封装为接口
根据上述来实现一下代码:
Sell接口:
public interface Sell {
int sellCPU(int count);
}
CPU工厂类:
public class BigCPUFactory implements Sell{
@Override
public int sellCPU(int count) {
return 2 * count;
}
}
MouBao代理商
public class MouBao implements Sell{
BigCPUFactory factory;
public MouBao(BigCPUFactory factory) {
this.factory = factory;
}
@Override
public int sellCPU(int count) {
int allMoney = factory.sellCPU(count);
System.out.println("我是MouBao代理商,每件我还要再加2块钱");
allMoney += 2*count;
return allMoney;
}
}
MouDuo代理商
public class MouDuo implements Sell{
BigCPUFactory factory;
public MouDuo(BigCPUFactory factory) {
this.factory = factory;
}
@Override
public int sellCPU(int count) {
int allMoney = factory.sellCPU(count);
System.out.println("我是MouDuo代理商,每件我还要再加1块钱");
allMoney += count;
return allMoney;
}
}
cpu消费者:
public class CPUConsumer {
public static void main(String[] args) {
System.out.println("========我要买5个CPU======");
MouBao mouBao = new MouBao(new BigCPUFactory());
MouDuo mouDuo = new MouDuo(new BigCPUFactory());
int money = mouBao.sellCPU(5);
System.out.println("=========通过MouBao买5个CUP花了: " + money);
money = mouDuo.sellCPU(5);
System.out.println("=========通过MouBao买5个CUP花了: " + money);
}
}
说说静态代理的好处:
- 实现简单,代码清晰,逻辑简单
缺点:
- 类与接口之间的耦合度太高。
假如我的Factory要卖的东西变多了,即Sell接口(代理商和目标类的共有方法)也会发生改变,那么我的所有代理商类就都要修改代码。 假如我的代理商跑满全球,那么代码要改到吐。
此时我们就会想,有没有一种方法可以不写各种代理类,但是可以实现代理类的对象呢?
当然是可以的。 就是java的动态代理,实现的原理就是反射机制。
这里说一下jdk动态代理的实现(利用proxy这个类)。
- 写一个实现InvocationHandler类
- 重写invoke方法
- 利用Proxy的静态类newProxyInstance方法创建并强转为目标类方法所属的接口类,
- 利用强转后的对象调用 目标类的方法
例:
Sell类
public interface Sell {
int sell(int count);
}
MyInvocationHander类
public class MyInvocationHander implements InvocationHandler {
Object target; //传入的目标类(这里指哪些厂)
public MyInvocationHander(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int money = (Integer) method.invoke(target, args);
money += 10;
return money;
}
}
CPUFactory
public class CPUFactory implements Sell{
@Override
public int sell(int count) {
return 2 * count;
}
}
Consumer:
public class Consumer {
public static void main(String[] args) {
// SellSomething factory = new UsbFactory();
CPUFactory factory = new CPUFactory();
InvocationHandler hander = new MyInvocationHander(factory);
Sell proxy = (Sell) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), hander);
//通过Proxy的静态方法来创建代理对象,并强转成目标类方法所属的接口类,这里是Sell
int money = proxy.sell(2);
System.out.println("通过动态代理买到2个CPU的花费为: " + money);
}
}
jdk提供的动态代理主要依靠java.lang.reflect包
里面有三个类
1.InvocationHandler接口,只包括一个方法 invoke()
这个方法是 我们这个代理对象要实现的具体逻辑代码,如上面写的
public class MyInvocationHander implements InvocationHandler {
Object target; //传入的目标类(这里指哪些厂)
public MyInvocationHander(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int money = (Integer) method.invoke(target, args);
money += 10;
return money;
}
}
invoke携带三个参数:
- proxy是jdk创建的代理对象,无需赋值
- method是通过反射获取到的目标类中的Method(方法)对象,
Method的使用是 method.invoke(目标类,参数)-- 具体可以学习java反射 - args是目标类中方法所需要的参数
聊聊动态代理的好处:
- 我们的invocationHandler不用实现接口,也就意味着不像静态代理一样需要写很多的代理实现类,当接口改变的时候,影响的也只有我们的Factory,大范围缩小了改动
- 很多都是固定写法,写熟了就很快