Java代理模式
首先举一个实例
消费者(客户端)--->商店(代理类)--->工厂(目标类)
当一个消费者想要购买可乐,中间的关系为,
客户端:消费者
代理类:负责进货并出售可乐的商店
目标类:生产可乐并出售的工厂
其中,代理类和目标类的功能一致,都是销售可乐。
代理模式的作用
1. 功能增强:在原有的功能上增加了新的功能
2. 访问限制:代理类不让你访问目标类
实现代理的方式
1. 静态代理
(1)代理类自己手动实现 ,自己创建Java类表示代理类
(2)每个代理类需要代理的目标类是确定的
静态代理实现简单容易理解,但也有局限性,当目标类的代理类数量很多时,如果目标类数量增加,代理类也需要成倍的增加(天猫可乐代理和京东可乐代理变成了天猫可口可乐代理、天猫百事可乐代理和京东可口可乐代理和京东百事可乐代理)。其次,如果之后在接口中增加一个方法,此时程序会出错,因为继承该接口的目标类和代理类中有未实现的方法,当类的数量越多,修改代码的工作量越大,出错的概率越高。
实现步骤:
(1)创建一个接口,定义卖可乐的方法
public interface ColaSell { float sell(int amount); }
(2)创建目标类(即工厂),实现(1)中的接口
// 目标类可口可乐,不接受消费者的单独购买
public class Coca implements ColaSell {
@Override
public float sell(int amount){
return amount * 2.5f;
}
}
(3)创建代理类(即商店),实现(1)中的接口
public class JingDong implements ColaSell {
// 声明代理的厂家具体为可口可乐
private final Coca factory = new Coca();
// 实现可乐销售功能
@Override
public float sell(int amount){
// 运费
float freight = 10;
// 代理向厂家发送订单,返回订单价格
float price = factory.sell(amount);
// 代理将可乐出售给消费者,消费者需要额外支付代理索要的利润
price += 0.5 * amount;
// 消费满59包邮
if (price >= 59) return price;
else return (price + freight);
}
}
(4)创建客户端类(即消费者),调用代理类的方法买可乐
public class Customer { public static void main(String[] args) { JingDong cola_JingDong = new JingDong(); float price_JingDong = cola_JingDong.sell(2); System.out.println("消费者从京东购买两瓶可乐共花费:" + price_JingDong + "元"); } }
2. 动态代理
当目标类数量很多时,可以使用动态代理,避免静态代理的缺点。
在动态代理中,即使目标类的数量很多,代理类的数量也可以很少,同时,当修改接口中的方法时,不会影响代理类。
动态代理的原理:在程序的执行过程中,利用JDK的反射机制,创建代理类对象,并动态地指定要代理的目标类。
动态:在程序的执行过程中,调用JDK提供的方法,创建代理类对象。
换句话说:动态代理就是一种创建Java对象的能力,让你不用创建JingDong类,就可以创建代理类对象。
动态代理常用的实现方式有两种:
(1)使用JDK动态代理:使用Java反射包(java.lang.reflect)中的类(InvocationHandler、Method、Proxy)和接口实现动态代理功能。
(2)通过CGLB动态代理:CGLB是一个第三方工具库,能创建代理对象,在很多框架(如Mybatis、Spring)中都可以使用。CGLB通过继承目标类,创建它的子类,重写子类中的同名方法,实现功能修改。CGLB对目标类的要求比较宽松,只要能继承就可以,因此目标类和其中的方法不能是final。
使用JDK的Proxy实现代理,要求目标类和代理类必须实现相同的接口,如果目标类没有接口就不能用该方法实现。对于无接口的类,想要实现动态代理就要使用CGLB来实现。
JDK动态代理的实现:
反射包java.lang.reflect中的3个类InvocationHandler、Method、Proxy
(1)InvocationHandler接口(调用处理器)中只有一个方法invoke(),代理类对象要实现的功能代码( 1.调用目标类方法 2.功能增强 )写在invoke()中
/*
invoke方法原型
Object proxy:JDK创建的代理类对象,不需要赋值
Method method:目标类方法,JDK提供Method对象
Object[] args:目标类方法参数,JDK提供
*/
public Object invoke(Object proxy, Method method, Object[] args)
用法:
1.创建类实现InvocationHandler接口
2.重写invoke()方法,把原来静态代理中代理类要实现的方法写在里面
(2)Method类可以通过method.invoke()执行某个目标类中的方法
method.invoke(目标类对象, 方法的参数)
(3)Proxy类中的静态方法newProxyInstance()代替new创建代理对象
/*
ClassLoader loader:类加载器,负责向内存中加载对象
Class<?>[] interfaces:目标对象实现的接口
InvocationHandler h:我们自己写的代理类对象要完成的功能
newProxyInstance返回值就是目标类对象的代理对象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

浙公网安备 33010602011771号