设计模式-代理模式(Proxy Pattern)

xiaoxiao2021-07-27  133

文章目录

一、概念1.1 作用 二、分类2.1 静态代理2.1.1 特点:2.1.2 缺点:2.1.3 实现: 2.2 jdk动态代理2.2.1 特点:2.2.2 缺点:2.2.3 实现: 2.3 CGLIB动态代理2.3.1 特点:2.3.2 实现: 三、小结

一、概念

为目标对象提供一种代理,以控制对其的访问。代理对象相当于中介,可以去掉功能服务或者增加添加额外功能服务。 举例: 今天我想去服装店A买件衣服,一般都是直接去A的实体店进行购买,但是今天下雨了不想出门,于是我就打开淘宝在A的官方旗舰店B把想要的衣服买了,那么B就是相当于A的一个代理。B又提供了其它一些服务,比如:七天无理由退换货、送货上门等(添加额外功能)。B又没有现场试穿等服务(去掉功能服务)。

1.1 作用

代理可以在不改变目标类原有代码的基础上拓展其功能。例如:对一些方法进行性能测试,添加操作日志等。AOP便是使用动态代理来实现拦截切入功能。

二、分类

2.1 静态代理

2.1.1 特点:

需要定义父类或者接口,代理对象和被代理对象需要同时继承父类或者实现该接口。

2.1.2 缺点:

每进行一个代理都要建立一个代理类,随着代理类增多会造成类膨胀。

2.1.3 实现:

有两种实现方式,继承与聚合,由于聚合的方式优于继承,这里只演示聚合的实现。 创建接口:目标类和代理类同时实现该接口。

public interface Moveable { void move(); }

目标对象:

public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车行驶中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }

代理对象:

public class CarProxy implements Moveable { private Car car; public CarProxy(Car car) { this.car = car; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); car.move(); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); } }

测试:

public class ProxyTest { public static void main(String[] args) { Car car = new Car(); Moveable proxy = new CarProxy(car); proxy.move(); } }

测试结果

汽车开始行驶...... 汽车行驶中...... 汽车结束行驶...... 汽车行驶时间:724毫秒!

2.2 jdk动态代理

2.2.1 特点:

代理目标必须实现一个或者多个接口。代理对象的生成不需要实现接口。代理对象通过JAVA的API动态生成。

2.2.2 缺点:

没有实现接口的类不能进行动态代理。

2.2.3 实现:

Java动态代理类位于java.lang.reflect包下,主要涉及以下两个类 (1) public interface InvocationHandler:该接口定义了一个抽象方法:

/** * @param proxy 代理类 * @param method 被代理的方法 * @param args 被代理方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;

该抽象方法在代理类中动态实现。 (2)public class Proxy:该类为动态代理类,该类产生代理类的方法为:

/** * @param loader 目标对象的类加载器 * @param interfaces 目标对象的接口类型 * @param h 事件处理函数,实现对目标对象的操作。 */ public static Object newProxyInstance( ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

创建接口:

public interface Moveable { void move(); }

目标对象:

public class Car implements Moveable { @Override public void move() { //实现开车 try { System.out.println("汽车行驶中......"); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }

代理工厂类:

public class TimeProxyFactory { //代理的目标对象 private Object target; public TimeProxyFactory(Object target) { this.target = target; } //获取目标对象 public Object getInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); Object obj = method.invoke(target, args); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); return obj; } }); } }

测试:

public class ProxyTest { public static void main(String[] args) { Moveable move = new Car(); TimeProxyFactory factory = new TimeProxyFactory(move); Moveable proxy =(Moveable) factory.getInstance(); proxy.move(); } }

测试结果

汽车开始行驶...... 汽车行驶中...... 汽车结束行驶...... 汽车行驶时间:123毫秒!

2.3 CGLIB动态代理

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

2.3.1 特点:

Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.因为它是使用继承方式,所以不能对final修饰的类进行代理。产生的代理类其实就是目标类的子类。

2.3.2 实现:

目标对象:

public class Train { public void move() { System.out.println("火车行驶中......"); } }

代理类:

public class CGLibProxy implements MethodInterceptor { //创建代理对象 public Object getProxyInstance(Class c) { //Enhancer可以为接口或者非接口类型创建一个子类作为代理类,可以拦截所有方法 Enhancer enhancer = new Enhancer(); //设置创建子类的类,也就是说为每个代理类创建子类 enhancer.setSuperclass(c); //设置回掉函数(因为MethodInterceptor继承了Callback类,默认执行intercept方法) enhancer.setCallback(this); //创建子类实例,返回去 return enhancer.create(); } /** * 拦截所有目标类方法的调用 * @param o 目标类的实例 * @param method 目标方法的反射对象 * @param objects 目标方法的参数 * @param proxy 代理类的实例 */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("汽车开始行驶......"); //代理类调用父类的方法,来实现代理类的方法 Object returnObject = proxy.invokeSuper(o, objects); long endTime = System.currentTimeMillis(); System.out.println("汽车结束行驶...... 汽车行驶时间:"+(endTime-startTime)+"毫秒!"); return returnObject; } }

测试:

public class ProxyTest { public static void main(String[] args) { Train train = (Train) new CGLibProxy().getProxyInstance(Train.class); train.move(); } }

测试结果

汽车开始行驶...... 火车行驶中...... 汽车结束行驶...... 汽车行驶时间:297毫秒!

三、小结

代理方式特点缺点静态代理需要定义父类或者接口,代理对象和被代理对象需要同时继承父类或者实现该接口,一次代理一个类随着代理类增多,出现大量重复代码,难维护,造成类膨胀jdk动态代理目标类需要实现至少一个接口,代理对象通过JAVA的API动态生成,可以代理一个借口的多个实现只能够代理实现了接口的目标类cglib动态代理代理类要实现MethodInterceptor接口,通过Enhancer创建目标类的子类为代理对象,所有也是通过继承关系创建代理类的,然后通过实现intercept(Object o, Method method, Object[] objects, MethodProxy proxy)方法对所有的方法进行拦截,添加增强处理,注意该方法中要通过代理类的invokeSuper调用父类的方法不能代理final修饰的类
转载请注明原文地址: https://www.6miu.com/read-4823387.html

最新回复(0)