java常用设计模式八:代理模式
一、概述
代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 其特征是代理类与委托类有同样的接口,真正的核心业务逻辑还是在实际对象里面。
二、为什么要使用代理模式
- 当客户端不想直接调用实际对象,或是客户端直接调用实际对象有困难。
- 比如:想在实际对象的业务方法执行前或执行后额外处理一些事情。但是又不能修改原来的实际对象的方法,这时候也可以用代理模式。
三、代理模式的分类
1、静态代理(在程序运行前,代理类的.class文件已经存在,所以称为静态代理)
1)原业务接口
public interface SourceObject { void operation(); }
2)原业务接口的实现类
public class SourceObjectImpl implements SourceObject { public void operation() { System.out.println("这是原业务核心方法"); } }
3)静态代理类
public class StaticProxy implements SourceObject { private SourceObjectImpl srcObj; public StaticProxy(SourceObjectImpl srcObj){ this.srcObj = srcObj; } public void operation() { System.out.println("原业务方法执行前:记录处理中日志"); srcObj.operation(); System.out.println("原业务方法执行前:记录完成日志"); } }
public class StaticProxy implements SourceObject { private SourceObject srcObj; public StaticProxy(SourceObject srcObj){ this.srcObj = srcObj; } public void operation() { System.out.println("原业务方法执行前:记录处理中日志"); srcObj.operation(); System.out.println("原业务方法执行前:记录完成日志"); } }
4)测试类
public class Client { public static void main(String[] args){ SourceObject srcObj = new SourceObjectImpl(); StaticProxy staticProxy = new StaticProxy(srcObj); staticProxy.operation(); } }
原业务方法执行前:记录处理中日志
这是原业务核心方法
原业务方法执行前:记录完成日志
由以上的结构可知:每个接口(SourceObject)有一个与之对应的代理类(StaticProxy),如果再有一个接口,那么就要同时新增一个代理类,这种情况在接口很多的时候,就会产生很多代理类。是否能只有一个代理类呢?当然是可以的,就是动态代理
2、动态代理(在程序运行前,代理类的.class文件不存在,是运行时序由Java反射机制动态生成)
动态代理主要是借助 类Proxy、接口InvocationHandler 来实现的。下面以一个具体的例子来说明 动态代理的过程
1)原业务接口
public interface SourceObject { void operation(); }
2)原业务接口的实现类
public class SourceObjectImpl implements SourceObject { public void operation() { System.out.println("这是原业务核心方法"); } }
3)新建动态代理类处理器(注意,该类并不是SourceObject的代理类,它并没有实现于接口SourceObject,因此它不能调用operation()方法,这是与静态代理 最大的不同之处,代理类是程序运行的时候才动态产生的。)
public class DynamicProxyHandler implements InvocationHandler { private Object srcObj;//被代理的实际对象,定义为Object类型表明,可以是任意对象 /** * 该方法负责动态创建代理类,并返回代理类的实例,这个实例的类继承于java.lang.reflect.Proxy,还实现了传入进来的srcObject的原业务接口。 * * @param srcObj * @return */ public Object getProxyInstance(Object srcObj) { this.srcObj = srcObj; return Proxy.newProxyInstance(srcObj.getClass().getClassLoader(), srcObj.getClass().getInterfaces(), this); } /** * 注意:客户端不会真正的显示调用该方法,当通过getProxyInstance取得的实例执行真正的方法时,该方法会执行。 * * @param proxy 参数传递的是动态生成的代理类的实例,本方法并没有使用它 * @param method 是调用的方法,即需要执行的方法 * @param args 是执行方法的参数 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("原业务方法执行前:记录处理中日志"); System.out.println("invoke 方法的第一个参数proxy 的类是:" + proxy.getClass().toString()); method.invoke(srcObj, args); System.out.println("原业务方法执行前:记录完成日志"); return null; } }
4)测试类
public class Client { public static void main(String[] args){ SourceObject srcObj = new SourceObjectImpl(); DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(); //为什么这里可以用SourceObject来接收getProxyInstance返回的实例呢?从后面的结果可知道动态产生的代理类实质上是继承于Proxy类,并实现于SourceObject SourceObject dynamicProxyInstance = (SourceObject)dynamicProxyHandler.getProxyInstance(srcObj); System.out.println("dynamicProxyInstance 的类是:================="+dynamicProxyInstance.getClass().toString()); System.out.println("dynamicProxyInstance 的父类是:==============="+dynamicProxyInstance.getClass().getSuperclass()); System.out.println("dynamicProxyInstance 实现的接口如下:==========="); Class<?>[] interfaces=dynamicProxyInstance.getClass().getInterfaces(); for(Class<?> i:interfaces){ System.out.println(i.getName()); } System.out.println("dynamicProxyInstance 的方法有:==============="); Method[] method=dynamicProxyInstance.getClass().getDeclaredMethods(); for(Method m:method){ System.out.println(m.getName()); } //执行真正的核心业务方法 System.out.println("dynamicProxyInstance 执行原业务方法:==============="); dynamicProxyInstance.operation(); //以下的代码是将动态生成的代理类保存到target的classes里面,便于查看。 byte[] bts = ProxyGenerator.generateProxyClass("$Proxy0", interfaces); FileOutputStream fos = null; try { fos = new FileOutputStream(new File("target/classes/proxy/demo/$Proxy0.class")); fos.write(bts); fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
dynamicProxyInstance 的类是:=================class com.sun.proxy.$Proxy0 dynamicProxyInstance 的父类是:===============class java.lang.reflect.Proxy dynamicProxyInstance 实现的接口如下:=========== proxy.demo.SourceObject dynamicProxyInstance 的方法有:=============== equals toString hashCode operation dynamicProxyInstance 执行原业务方法:=============== 原业务方法执行前:记录处理中日志 invoke 方法的第一个参数proxy 的类是:class com.sun.proxy.$Proxy0 这是原业务核心方法 原业务方法执行前:记录完成日志
由以上结果可知:程序运行时动态生成了一个代理类com.sun.proxy.$Proxy0,它的父类是Proxy,并且还实现了接口SourceObject。这个代理类是由Proxy的 newProxyInstance 方法生成的。生成的代理类的源代码如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import proxy.demo.SourceObject; public final class $Proxy0 extends Proxy implements SourceObject { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void operation() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("proxy.demo.SourceObject").getMethod("operation"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
当调用 dynamicProxyInstance.operation() 的时候,实质上就是调用了以上生成的代理类中红色标注的方法。
super.h.invoke(this, m3, (Object[])null);
super就是指父类Proxy,h就是指InvocationHandler的实例,这里应该是传入的子类DynamicProxyHandler 的实例,所以h.invoke方法,就是执行DynamicProxyHandler的invoke方法。