一、与动态代理的恩怨
学了一段时间了(大学四年+待业半年),感觉自己学习了一个寂寞,在此发誓要每天回顾一个旧的小知识点,把东西都搞懂。
动态代理之前对它的概念及其模糊,代理代理,不就是帮他人办事嘛,但是具体的实现还是不明白。
看了看视频,看了一些大佬的文章,有一点点的理解,记录一下,顺便希望可以得到大家的指正。
二、概念
讲动态代理的概念之前,先说一下“代理”
代理
打个比方吧,太专业的词藻说不出来。
我要买草莓果酱,我需要到淘宝找卖草莓果酱的商家下单,商家要到草莓果酱的工厂,拿到果酱,寄快递给我。
简而言之:
1、顾客找卖草莓果酱的淘宝商家
2、商家找草莓果酱的工厂
这个过程中,淘宝卖家就是“代理”,顾客要通过淘宝卖家这个“代理”才能够买到果酱。
小可爱疑问:为什么顾客不直接找工厂买呢?
顾客没工厂资源,你谁呀?还有你直接找工厂买了,“代理”怎么中间商赚差价,还有一点比较重要的后面说。
·········静态代理
代理—|··············JDK动态代理
·········动态代理—|
·························CGLIB动态代理
静态代理
定义一个目标类的接口:功能是卖果酱,返回价格
//目标类接口
public interface Jam {
//返回价格
int sellJam(int number);
}
定义一个工厂实现这个目标类的接口,返回工厂的价格
public class StrawberryFactory implements Jam {
@Override
public int sellJam(int number) {
//返回工厂价格
return 10*number;
}
}
定义一个商家也要实现这个目标类的接口(商家也要卖果酱),返回商家的价格
public class StrawberryMerchant implements Jam {
//获取目标类:找到一个做草莓果酱工厂
StrawberryFactory factory = new StrawberryFactory();
@Override
//实现卖果酱的功能
public int sellJam(int number) {
//向工厂下单,告诉工厂需要多少草莓果酱
int factoryMoney = factory.sellJam(number);//返回工厂价格
//收取辛苦费用
int money = factoryMoney+10;
//给顾客
return money;
}
}
顾客下单
public class Client {
public static void main(String[] args) {
//获取代理对象:卖草莓果酱的商家
StrawberryMerchant merchant = new StrawberryMerchant();
int money = merchant.sellJam(10);
System.out.println("10罐草莓果酱的价格是"+money);
}
}
执行结果
10罐草莓果酱的价格是110
Process finished with exit code 0
如果我现在还想买苹果果酱呢?那就还需要找一个卖苹果果酱的商家,这个苹果果酱的商家找加工苹果果酱的工厂。
如果还想买葡萄果酱呢?这样有点麻烦,还不如找一个既卖草莓果酱,又卖苹果果酱,还卖葡萄果酱的淘宝卖家
---------这个需求动态代理可以实现
··············优点: 1、实现简单 2、容易理解
静态代理----|
··············缺点: 1、当目标类增加了,代理类也需要增加。代理类数量多。2、当接口中增加或者修改一个功能,会影响实现这个接口的类。
动态代理(jdk)
jdk动态代理是基于反射来实现的。
使用动态代理有三个要点:
1、必须实现 InvocationHandler 接口,表明该类是一个动态代理执行类。
2、InvocationHandler 接口内有一实现方法如下:
public Object invoke(Object proxy, Method method, Object[] args)
使用时需要重写这个方法
3、获取代理类,需要使用
Proxy.newProxyInstance(Clas loader, Class[] interfaces, InvocationHandler h)
这个方法去获取Proxy对象(Proxy 类类型的实例)。
注意到 Proxy.newProxyInstance 这个方法,它需要传入 3 个参数。解析如下:
// 第一个参数,是类的加载器
// 第二个参数是委托类的接口类型,证代理类返回的是同一个实现接口下的类型,保持代理类与抽象角色行为的一致
// 第三个参数就是代理类本身,即告诉代理类,代理类遇到某个委托类的方法时该调用哪个类下的invoke方法
Proxy.newProxyInstance(Class loader, Class<?>[] interfaces, InvocationHandler h)
再来看看 invoke 方法,用户调用代理对象的什么方法,实质上都是在调用处理器的invoke 方法,通过该方法调用目标方法,它也有三个参数:
// 第一个参数为 Proxy 类类型实例,如匿名的 $proxy 实例
// 第二个参数为委托类的方法对象
// 第三个参数为委托类的方法参数
// 返回类型为委托类某个方法的执行结果
public Object invoke(Object proxy, Method method, Object[] args)
开始买果酱
目标类:
//苹果果酱工厂
public class AppleFactory implements Jam {
@Override
public int sellJam(int number) {
//返回工厂价格
return 5*number;
}
}
//草莓果酱工厂
public class StrawberryFactory implements Jam {
@Override
public int sellJam(int number) {
//返回工厂价格
return 10*number;
}
}
代理
public class MerchantHandler implements InvocationHandler {
//创建一个工厂,是什么工厂并不知道
private Object factory = null;
public MerchantHandler(Object factory) {
this.factory = factory;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//向工厂下单,返回工厂价
int factoryMoney = (int) method.invoke(factory, args);
//收取辛苦费
int money = factoryMoney+10;
return money;
}
}
顾客下单
public class Client {
public static void main(String[] args) {
//获取目标类对象:需求是啥?要草莓果酱和苹果果酱,
Jam strawberry = new StrawberryFactory();
Jam apple = new AppleFactory();
//引入MerchantHandler,需求告诉handler
MerchantHandler strawberryHandler = new MerchantHandler(strawberry);
MerchantHandler appleHandler = new MerchantHandler(apple);
//获取代理对象
Jam sProxy = (Jam) Proxy.newProxyInstance(strawberry.getClass().getClassLoader(),
strawberry.getClass().getInterfaces(), strawberryHandler);
Jam aProxy = (Jam) Proxy.newProxyInstance(apple.getClass().getClassLoader(),
apple.getClass().getInterfaces(),appleHandler);
//调用方法
int sMoney = sProxy.sellJam(10);
int aMoney = aProxy.sellJam(10);
System.out.println("10罐草莓果酱的价格是"+sMoney);
System.out.println("10罐苹果果酱的价格是"+aMoney);
}
}
执行结果
10罐草莓果酱的价格是110
10罐苹果果酱的价格是60
Process finished with exit code 0
java | 什么是动态代理? - JavaFish的文章 - 知乎
https://zhuanlan.zhihu.com/p/65501610