-
代理模式
代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客类和目标对象之间起到中介的作用。 -
代理模式的作用
A、控制访问
B、增强功能 -
代理模式分类
静态代理与动态代理 -
代理的实现方式
需求:用户需要购买 u 盘,u 盘厂家不单独接待零散购买,厂家规定一次最少购买 1000个以上,用户可以通过淘宝的代理商,或者微商哪里进行购买。
淘宝上的商品,微商都是 u 盘工厂的代理商, 他们代理对 u 盘的销售业务。
用户购买-------代理商(淘宝,微商)----- u 厂家(金士顿,闪迪等不同的厂家)
设计这个业务需要的类:
a. 商家和厂家都是提供 sell 购买 u 盘的方法。定义购买 u 盘的接口 UsbSell
b. 金士顿(King)对购买 1 千以上的价格是 85, 3 千以上是 80, 5 千以上是 75。 单个 120
元。定义 UsbKingFactory 类,实现 UsbSell
c. 闪迪(San)对购买 1 千以上的价格是 82, 3 千以上是 78, 5 千以上是 72。 单个 120 元。
定义 UsbSanFactory 类,实现 UsbSell
d. 定义淘宝的代理商 TaoBao ,实现 UsbSell
e. 定义微商的代理商 WeiShang, 实现 UsbSell
f. 定义测试类,测试通过淘宝, 微商购买 u 盘4.1 静态代理
(1) 定义业务接口
定义业务接口 UsbSell(目标接口),其中含有抽象方法 sell(int amount), sell 是目标方
法。
(2) 定义接口实现类
目标类 UsbKingFactory(金士顿 u 盘),该类实现了业务接口。
(3) 代理商接口
public class Agent implements UsbSell {
private UsbKingFactory factory = new UsbKingFactory();
public float sell(int amount) {
float price = factory.sell(amount);
// 在单价之上增加25元的利润
return price + 25;
}
}
(4) 客户端调用者,购买商品类
public class ShopApplication {
public static void main(String[] args) {
float price = 0.0f;
// 代理商
Agent agent = new Agent();
price = agent.sell(1);
System.out.println("代理商购买价格:" + price);
}
}
(5) 静态代理缺点
代理类只服务于一种类型的目标类,如果要服务多个类型。势必要为每一种目标类都进行代理,静态代理在程序规模稍大时就无法胜任了,代理类数量过多。
4.2 动态代理
动态代理是指代理类对象在程序运行时由 JVM 根据反射机制动态生成的。动态代理不需要定义代理类的.java 源文件。
动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。
动态代理的实现方式常用的有两种:使用 JDK 代理代理,与通过 CGLIB 动态代理。
4.2.1 jdk 的动态代理
jdk 动态代理是基于 Java 的反射机制实现的。使用 jdk 中接口和类实现代理对象的动态创建。
Jdk 的动态要求目标对象必须实现接口,这是 java 设计上的要求。
从 jdk1.3 以来,java 语言通过 java.lang.reflect 包提供三个类支持代理模式 Proxy, Method和 InovcationHandler
(1) InvocationHandler 接口
InvocationHandler 接口叫做调用处理器,负责完成调用目标方法,并增强功能。
通 过 代 理 对 象 执 行 目 标 接 口 中 的 方 法 , 会 把 方 法 的 调 用 分 派 给 调 用 处 理 器(InvocationHandler)的实现类,执行实现类中的 invoke()方法,我们需要把功能代理写在 invoke()方法中 。
InvocationHandler 接口中只有一个方法:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
在 invoke 方法中可以截取对目标方法的调用。在这里进行功能增强。Java 的动态代理是建立在反射机制之上的。
实现了 InvocationHandler 接口的类用于加强目标类的主业务逻辑。这个接口中有一个方法 invoke(),具体加强的代码逻辑就是定义在该方法中的。通过代理对象执行接口中的方法时,会自动调用 invoke()方法。
invoke()方法的介绍如下:
proxy:代表生成的代理对象
method:代表目标方法
args:代表目标方法的参数
JDK动态代理的实现
jdk 动态代理是代理模式的一种实现方式,其只能代理接口。
实现步骤
1、新建一个接口,作为目标接口
2、为接口创建一个实现类,是目标类
3、创建类实现 java.lang.reflect.InvocationHandler 接口,调用目标方法并增加其他功能代码
4、创建动态代理对象,使用 Proxy.newProxyInstance()方法,并把返回值强制转为接口类型。
public class ShopApplication2 {
public static void main(String[] args) {
// 创建代理
UsbKingFactory target = new UsbKingFactory();
// 创建调用处理器
MySellHandler proxyHandler = new MySellHandler(target);
// 创建jdk动态代理
UsbSell usbSell = (UsbSell) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), proxyHandler);
// 通过代理对象执行业务方法,实现利润增加
float price = usbSell.sell(1);
System.out.println("动态代理价格:" + price);
}
}
执行流程:
Client --> 动态代理对象Proxy --> InvocationHandler 调用处理器截取对象方法的调用。
5. cgLib 代理
CGLIB(Code Generation Library)是一个开源项目。是一个强大的,高性能,高质量的 Code 生成类库,它可以在运行期扩展 Java 类与实现 Java 接口。它广泛的被许多 AOP 的框架使用,例如 Spring AOP。
使用 JDK 的 Proxy 实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。
但对于无接口的类,要为其创建动态代理,就要使用 CGLIB 来实现。CGLIB 代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB 生成动态代理,要求目标类必须能够被继承,即不能是 final 的类。
cglib 经常被应用在框架中,例如 Spring ,Hibernate 等。Cglib 的代理效率高于 Jdk。对于 cglib 一般的开发中并不使用。做了一个了解就可以