- 前言
- 1、何为代理
- 2、静态代理
- 3、动态代理
1、何为代理java的设计模式中有一项设计模式叫做代理模式,所谓代理模式,就是通过代理方来操作目标对象,而不是自己直接调用。
代理又分为静态代理和动态代理,静态代理就是针对每个被代理对象写一个代理类,操作不够优雅;
动态代理,可以根据接口动态的生成代理类,这动态生成的类不需要自己书写,jdk帮你完成了。该博客总结于动力节点视频教程,主要讲述了JDK动态代理(AOP)使用及实现原理分析。
动态代理基于反射机制,在我们日常生活中有许多与代理有关的例子:代购、中介等。
比如说有一家美国大学,可以对全世界进行招生。这时就需要一个留学中介(代理) 替大学在全球各地招生。此时中介就是学校的代理,中介替学校完成招生功能。
代理特点:
- 中介和学校要做的事情是一致的:招生
- 中介是学校的代理,学校是目标
- 中介不能白白工作,需要收取代理费
- 中介(代理)不让你直接访问目标
为什么找中介(代理):
- 中介是专业的
- 学生没有能力直接访问学校(学校离得远不说,可能还不接受个人来访)
开发中也会遇到这样情况:我有一个A类,本来调用C类的方法完成某个功能,但是C不让A调用。
就在A和C之间创建一个代理类B,C类允许B类进行访问,此时情况就是:A——>B——>C
代理模式:为其他对象提供一种代理控制对这个对象的访问。当一个对象不适合直接引用另一个对象,这时代理对象就在客户类和目标对象之间起到中介作用
换句话说,使用代理对象,是为了不修改目标类的基础上,增强主业务逻辑
代理模式的作用:
- 功能增强:原有的功能上增加新功能
- 控制访问:代理类不让客户访问目标
实现代理的方式:
- 静态代理
- 动态代理
静态代理:代理类自己手动实现,需要自己创建Java类表示代理类,同时代理的目标类时固定的
代码案例:买家购买U盘
卖U盘方法的接口:
public interface UsbSell {
float sell(int amount);
}
代理类:
public class TaoBao implements UsbSell {
private UsbSell factory = new UsbKingFactory();
@Override
public float sell(int amount) {
//向厂家发送订单
float price = factory.sell(amount); //厂家价格
//商家 加价售卖
//增强功能,代理类完成目标类方法调用后,增强了功能
price = price + 25;
//目标类方法调用后,做的其他功能都是增强的意思
System.out.println("商家给您返回一个优惠券");
return price;
}
}
目标类:
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
return 85.0f;
}
}
测试类:
public class shopMain {
public static void main(String[] args) {
//创建代理对象
TaoBao taoBao = new TaoBao();
float price = taoBao.sell(1);
System.out.println("通过商家购买U盘单价为:" + price); //单价为 110.0元
}
}
通过上述代码,我们可以直到静态代理的缺点:
- 当目标类增加了,代理类可能需要成倍增加
- 当接口中功能增加、修改,会影响众多实现类、厂家类、代理类
动态代理可以解决以上缺点!
3、动态代理动态代理优点:
- 在静态代理中目标类很多情况下,可以使用动态代理,解决静态代理的确定。
- 动态代理中目标类即便很多,代理类数量也可以很少。当我们修改接口中的方法,不会影响代理类
动态代理概念:
在程序的执行过程中,使用JDK反射机制,创建代理类对象,并动态的指定要代理的目标类。动态代理是一种创建Java对象的能力。
动态代理实现方式:
- JDK动态代理:使用Java反射包(java.lang.reflect)中的类和接口实现动态代理的功能。包中有三个类:InvocationHandler、Method、Proxy。该代理方式要求目标类必须有接口
- CGLIB动态代理(了解):cglib是第三方工具库,能够创建代理对象。cglib的原理是继承,通过创建子类继承目标类,在子类中重写父类中同名的方法,实现功能的修改。cglib对目标类的要求比较宽松,只要能继承就可以。在很多框架中使用过cglib,例如:Mybatis、Spring。cglib的代理效率高于JDK代理
JDK动态代理实现:
1):InvocationHandler接口:就一个方法invoke(),表示代理对象要执行的功能代码。
//方法原型 public Object invoke(Object proxy,Method method,Object[] args); //参数 Object proxy: jdk创建的代理对象,无需赋值,jdk提供 Method method: 目标类中的方法,jdk提供method对象 Object[] args: 目标类中方法的参数,jdk提供
使用方式:
- 创建一个类实现接口InvocationHandler
- 重写invoke(),把原来静态代理中代理类要完成的功能写在invoke中
2):Method类:表示方法, 确切的说就是目标类中的方法,通过Method可以执行某个目标类中的方法,Method.invoke(目标对象,方法参数)
注意: 该invoke只是恰巧和InvocationHandler中的invoke方法同名而已,并不是同一个方法!
3):Proxy类:核心对象,创建代理对象。之前创建对象通过new,现在使用Proxy类的方法代替new创建对象。通过静态方法 newProxyInstance(),作用是创建代理对象
//返回值就是代理对象
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
方法参数:
1.ClassLoader loader: 类加载器,负责向内存中加载对象。使用反射获取对象的ClassLoader
A.getClass().getClassLoader(),目标对象的类加载器
2.Class> interfaces: 接口,目标对象所实现的接口,也是反射获取的
3.InvocationHandler h: 我们自己写的,代理类要完成的功能
实现动态代理步骤:
- 创建接口,定义目标类要完成的功能
- 创建目标类实现接口
- 创建InvocationHandler接口实现类,在invoke方法中完成代理类的功能:调用目标方法,增强功能
- 使用Proxy静态方法创建代理对象,并把返回值转为接口类型
代码实现:
方法接口:
//方法接口
public interface UsbSell {
float sell(int amount);
}
目标类:
//目标类
public class UsbKingFactory implements UsbSell {
@Override
public float sell(int amount) {
//目标方法
System.out.println("目标类中执行了sell目标方法");
return 85.0f;
}
}
InvocationHandler接口实现类:
//必须实现InvocationHandler接口,完成代理类要做的功能(调用目标方法,执行功能增强)
public class MySellHandler implements InvocationHandler {
//目标对象
private Object target = null;
//动态代理;target目标对象是活动的,不是固定的,需要传入,然后创建代理
public MySellHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//向厂家发送订单
//float price = factory.sell(amount); //厂家价格
Object res = method.invoke(target, args); //执行目标方法,等价于上一行注释
//商家 加价售卖
//增强功能,代理类完成目标类方法调用后,增强了功能
//price = price + 25;
if (res != null) {
Float price = (Float) res;
price += 25;
res = price;
}
//目标类方法调用后,做的其他功能都是增强的意思
System.out.println("商家给您返回一个优惠券");
return res;
}
}
测试类:
//测试类
public class MainShop {
public static void main(String[] args) {
//创建代理对象
//1.创建目标对象
UsbSell factory = new UsbKingFactory();
//2.创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(factory);
//3.创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(), handler);
//4.通过代理对象执行方法
float price = proxy.sell(1);
System.out.println("通过动态代理对象,调用方法:" + price);
}
}
动态代理能做什么?
可以在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码
例如:我们的项目中有一个功能是别人开发的,我可以使用。但是该功能不能满足我项目的需求
我需要自己增加一些代码,这时候就可以使用代理实现,而不用修改原来的代码



