在 Java 中代理模式一般分为两种,静态代理和动态代理.
代理模式指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.
代理模式一般会有三个角色:
抽象角色:指代理角色和 真实角色对外提供的公共方法,一般为一个接口
真实角色:需要实现抽象角色接口,定义了真实角色所要实现的 业务逻辑,以便代理角色调用.也就是真正的业务逻辑.
代理角色:需要实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作.将统一的流程都控制到代理角色中处理.
而访问者不再访问真实角色,而是去访问代理角色。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。一般来说,被代理对象和代理对象是一对一的关系,当然一个代理对象对应多个被代理对象也是可以的。
静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代理对象会出现扩展能力差的问题。
指在使用时再创建代理类的实例
优点
只需要一个动态代理类,就可以解决创建多个静态代理类的问题,避免重复多余的代码
缺点
相比于静态代理,效率低.动态代理需要先通过 Java 反射机制,创建 Proxy 类来间接调用目标方法.
应用场景局限, 因为 Java 的单继承特征(每个代理类都继承了 Proxy 类),即只能针对接口创建代理类,不能针对类创建代理类.
在动态机制中,有两个重要的类和接口,一个是 InvocationHandler 接口,一个 Proxy 类,这两个是实现动态代理必须用到的.
InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。
public class DynamicProxy implements InvocationHandler { //持有的真实对象 private Object factory; public Object getFactory() { return factory; } public void setFactory(Object factory) { this.factory = factory; } //获取到代理类实例 public Object getProxyInstance() { return Proxy.newProxyInstance(factory.getClass().getClassLoader() , factory.getClass().getInterfaces(), this); } //当方法被调用时,会调用 InvocationHandler 的 invoke 方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doSthAfter(); Object result = method.invoke(factory, args); doSthBefore(); return result; } private void doSthAfter() { System.out.println("调用之前进行操作"); } private void doSthBefore() { System.out.println("调用之后进行操作"); } }
抽象代理接口
public class AbstractPart{ void methodA() }
真正实现业务逻辑的类
public class RealPart implements AbstractPart { @Override public void methodA() { System.out.println("真实实现!"); } }
使用动态代理
DynamicProxy dynamicProxy = new DynamicProxy(); dynamicProxy.setFactory(new RealPart()); AbstractPart proxyInstance = (AbstractPart) dynamicProxy.getProxyInstance(); proxyInstance.methodA();
当我们创建一个动态代理时,最重要的一行代码是:
Proxy.newProxyInstance(factory.getClass().getClassLoader() , factory.getClass().getInterfaces(), this);
在newProxyInstance方法中,会先获取到动态创建的代理对象,然后获取构造器,创建实例对象.
Class<?> cl = getProxyClass0(loader, intfs); final Constructor<?> cons = cl.getConstructor(constructorParams); return cons.newInstance(new Object[]{h});
在这个方法内部使用了 proxyClassCache.get
方法来获取代理类,通过这个方法我们可以知道 JDK 内部使用了某种缓存机制缓存了我们的代理类 class 对象,get 方法接受的参数是被代理类的类加载器和类实现的接口.
在 JDK 内部,会生成一个派生自 Proxy 的类
public final class $Proxy0 extends Proxy implements ICook { private static Method m1; private static Method m2; private static Method m3; 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})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } 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 void methodA() throws { try { super.h.invoke(this, m3, (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)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.caimuhao.examples.javaadvance.proxy.dynamic").getMethod("methodA", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }
在这个类中,有我们代理对象的所有方法,当我们调用创建动态代理返回的对象的方法时,其实调用的是 h.invoke
方法,这个 h 对象就是我们在调用 Proxy.newProxyInstance
实例时,传入的 this 参数,也就是动态代理 中的 invoke
方法.这样我们就可以代理到其它类,在其它类方法执行前后加入一些我们自己的业务逻辑.