原文链接:jdk动态代理 – 编程屋
目录
1 前言
代理模式:是指为其他对象提供一种代理以控制对这个对象的访问,在某些情况下,一对象不适合或者不能直接引用另外一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。
使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。客户类真正想要访问的对象是目标对象,但客户真正能够访问的是代理对象,客户类对目标对象的访问是通过访问代理类来实现的。
作用:
1 功能增强:在你原有的功能上,增加了额外的功能,新增加的功能叫做功能增强
2 控制访问:代理类不让你访问目标
2 代理方式
2.1 静态代理
1)代理类是自己手工实现的
2)自己所需要代理的对象是确定的
2.1.1 静态代理实现
步骤1 :定义一个卖u盘的接口
步骤2:创建一个厂家的类,实现步骤一中卖u盘的方法
步骤3:创建商家(代理),实现步骤一中的接口
步骤4:创建客户端类,调用商家方法买u盘
代码实现:
步骤一:定义一个卖u盘的接口
public interface UsbSell {
/**
* 定义一个方法 厂家,商家都要用完成的功能
* @param amount 购买的数量
* @return
*/
float sell(int amount);
}
步骤2:创建一个厂家的类,实现步骤一中卖u盘的方法
//目标类 厂家只向中间商供货,不会想个体小商户供货
public class UsbFactory implements UsbSell {
@Override
public float sell(int amount) {
//定义一个U盘的价格是65元
float price = 65.0f;
return amount*price;
}
}
步骤3:创建商家(代理),实现步骤一中的接口
//代理类-----中间商
public class TaoBao implements UsbSell {
//代理的是金士顿 定义目标厂家类
private UsbFactory usbFactory = new UsbFactory();
@Override
public float sell(int amount) {
//调用目标方法
float price = usbFactory.sell(amount);
price = (price + 15)*amount;
return price;
}
}
步骤4:创建客户端类,调用商家方法买u盘
@Test
public void test7(){
TaoBao taoBao = new TaoBao();
float sell = taoBao.sell(80);
System.out.println("***总金额****"+sell); //***总金额****417200.0
}
可见,我们通过代理中间商去购买u盘的时候,被中间商每个u盘都赚了15元的差价。
我们可以发现,这个加价格的这个功能时我们在调用了目标类之后进行的,其实这一步就相当于我们一个功能的增强(代理类在完成功能时会进行一个增强),同时我们也可进行一些其他的功能增强,比如:返回优惠券或者红包,只要是在我们原有功能完成之后进行的功能都属于功能增强。
静态代理优缺点:
优点:实现方便简单,容易理解
缺点:目标类增加时,代理会增加。接口功能修改了商家和代理类都有改动
2.2 动态代理
动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理的目标类。(动态代理是一种创建Java对象的能力,省去了我们自己创建代理类对象)
Spring Aop底层实现,是通过jdk动态代理或者CGlib代理在运行时期在对象初始化阶段织入代码的
jdk动态代理是基于接口实现的
CGlib是基于类的集成实现的
2.2.1 动态代理实现的几种方式
1 cglib动态代理:cglib是第三方的工具库,创建代理对象,cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中重写父类中重名的方法,实现功能的修改
因为cglib是继承,重写方法,所以需要要继承的类不能是final的,重写的方法也不能是final的。cglib在mybatis,spring中的框架中都有使用
2 jdk的动态代理:使用Java反射包中的类和接口实现动态代理的功能。反射包:Java lang reflect 三个类:InvocationHandler ,Method,Proxy
1)InvocationHandler接口(调用处理器):中一个方法invoke().表示代理对象要执行的功能代码,代理类功能要完成的功能就写在invoke()方法中。
代理类完成的功能:
调用目标方法,执行目标方法的功能
功能增强,在目标方法调用时,增强功能
方法原型:
参数:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法,jdk提供method对象
Object[] args:目标类中方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
2)Method:表示方法的(目标类中的方法)
作用:通过Method可以执行某个目标类的方法 Method.invoke(目标对象,目标参数);
注意:此处的invoke方法和InvocationHandler类中的invoke方法不是同一个
3)Proxy类:创建代理对象,不在通过之前那种new 类的构造方法来创建对象了,而是使用Proxy类中的方法,代替new的使用
方法;静态方法 newProxyInstance()
参数:
ClassLoader loader 类加载器:负责向内存中加载对象的。使用反射获取对象的ClassLoader(比如:类B>>B.getCalss().getClassLoader())目标对象的类加载器
Class<?> interface:目标对象实现的接口,也是通过反射获取的
InvocationHandler h:代理类要完成的功能
public static Object newProxyInstance(ClassLoader loader,
Class<?> interface,InvocationHandler h)
2.2.2 实现动态代理
步骤一:创建接口,定义目标类要完成的功能
public interface UsbSell {
float sell(int amount);
}
步骤二:创建目标类实现接口
public class UsbSellFactory implements UsbSell{
@Override
public float sell(int amount) {
System.out.println("进入目标类中执行的方法");
return 65.0f*amount;
}
}
步骤三:创建InvocationHandler接口的实现类,在invoke方法中完成代理的功能(1 调用目标方法2增强功能)
以上只是部分内容,为了维护方便,本文已迁移到新地址:jdk动态代理 – 编程屋