代理是一种常用的设计模式,给某个对象提供一个代理,并由代理对象来控制对真实对象的访问。它的方式就是让代理类持有目标类的实例,并在对目标类进行操作的前后加入一层代理操作。
1. 静态代理 静态代理类在编译时就实现好了,它在Java编译完成后就是一个确定的class文件
Proxy:代理主题,用来代理和封装真实主题;
Subject:抽象主题,定义代理类和真实主题的公共对外方法,即需要代理的方法。
RealSubject:真实主题,真正实现业务逻辑的类;
客户端直接面对的是代理类,通过代理类对目标类进行访问。这样当需要在访问过程中进行一些操作时,就可以不用修改已有的实现类,只需将操作加到代理类中。
示例 Subject 1 2 3 4 public interface Handler { void handle (String arg) ; }
RealSubject 1 2 3 4 5 6 7 public class HandlerImpl implements Handler { @Override public void handle (String arg) { System.out.println("handle[" + arg + "]" ); } }
Proxy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class HandlerProxy implements Handler { private Handler handler; public HandlerProxy (Handler target) { this .handler = target; } @Override public void handle (String arg) { System.out.println("before..." ); handler.handle(arg); System.out.println("after..." ); } }
Client 1 2 3 4 5 6 7 public class Client { public static void main (String[] args) { Handler handler = new HandlerImpl(); HandlerProxy handlerProxy = new HandlerProxy(handler); handlerProxy.handle("test" ); } }
通过代理类可以避免对目标类的修改,并增加了期望的行为,同时保证了调用者所调用的类型不变。但是这种代理方式显得不够灵活,如果接口发生了改变,必须同时改变目标类和代理类。
假设现在有一个明确的代理操作,比如打印方法的执行耗时,那么如果目标接口的方法非常多,代理类就会显得很臃肿。如果希望将这个代理操作应用到更多不同的接口实现类上,那就更麻烦了,要给每个接口都定制一个代理类,可能你会想到用工厂模式来让代码结构更新清晰一点,但如此臃肿又麻烦的方式,显然早已违背了设计原则的初衷。
2. 动态代理 2.1. JDK动态代理 对于上面代理模式存在的问题,JDK肯定也想到了,于是提供了一种动态的方式来创建代理类,利用反射在运行时进行创建。
它提供了InvocationHandler
让你来定义期望的代理行为
java.lang.reflect.InvocationHandler 1 2 3 public interface InvocationHandler { public Object invoke (Object proxy, Method method, Object[] args) throws Throwable ; }
并提供了一个工厂方法,给你来创建代理类,这样你就可以将代理行为应用到任何接口上了
java.lang.reflect.Proxy 1 public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ;
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ProxyHandler implements InvocationHandler { Object target; public ProxyHandler (Object target) { this .target = target; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { before(method, args); Object result = method.invoke(target, args); after(method, args); return result; } private void before (Method method, Object[] args) { System.out.println("before " + method.getName()); } private void after (Method method, Object[] args) { System.out.println("after " + method.getName()); } }
1 2 3 4 5 6 7 8 9 10 public class ProxyFactory { public static <T> T createProxy (T target) { ClassLoader classLoader = target.getClass().getClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); ProxyHandler proxyHandler = new ProxyHandler(target); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxyHandler); } }
1 2 3 4 5 6 7 8 9 public class Client { public static void main (String[] args) { System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" ); Handler proxy = ProxyFactory.createProxy(new HandlerImpl()); proxy.handle("xxx" ); } }
所以,利用JDK动态代理,只要在InvocationHandler
中定义好代理行为,然后在创建代理类再决定将代理行为添加到哪些接口上。只要代理行为是确定的,那么不管要对多少目标类进行代理,以及目标类如何变化,都可以轻松应付了,我们还可以在定义代理行为时根据method
来进行判断取舍
实现
通过工具jad -sjava $Proxy0.class
可以看一下生成的代理类class:
它实现了目标类的所有接口,并持有一个InvocationHandler
的实例。而InvocationHandler
中又持有了目标类的实例,并定义了代理行为。这样代理类最终将操作全部委托给了InvocationHandler
,也就不直接依赖于目标类了,实现了解耦。
这样的好处是很明显的,你只要定义好了代理行为,并给定接口,就能创建代理类实例进行执行 ,这也是Mybatis、Feign等能够实现接口注解的基础。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public final class $Proxy0 extends Proxy implements Handler { public $Proxy0(InvocationHandler invocationhandler){ super (invocationhandler); } public final boolean equals (Object obj) { try { return ((Boolean)super .h.invoke(this , m1, new Object[] {obj})).booleanValue(); }catch (Error _ex) { }catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } public final void query (String s) { try { super .h.invoke(this , m4, new Object[] {s}); return ; }catch (Error _ex) { }catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } public final String toString () { try { return (String)super .h.invoke(this , m2, null ); }catch (Error _ex) { }catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } public final void delete (String s) { try { super .h.invoke(this , m3, new Object[] {s}); return ; }catch (Error _ex) { }catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } public final int hashCode () { try { return ((Integer)super .h.invoke(this , m0, null )).intValue(); }catch (Error _ex) { }catch (Throwable throwable){ throw new UndeclaredThrowableException(throwable); } } private static Method m1; private static Method m4; private static Method m2; private static Method m3; private static Method m0; static { try { m1 = Class.forName("java.lang.Object" ).getMethod("equals" , new Class[] { Class.forName("java.lang.Object" ) }); m4 = Class.forName("org.eto.essay.Handler" ).getMethod("query" , new Class[] { Class.forName("java.lang.String" ) }); m2 = Class.forName("java.lang.Object" ).getMethod("toString" , new Class[0 ]); m3 = Class.forName("org.eto.essay.Handler" ).getMethod("delete" , new Class[] { Class.forName("java.lang.String" ) }); m0 = Class.forName("java.lang.Object" ).getMethod("hashCode" , new Class[0 ]); }catch (NoSuchMethodException nosuchmethodexception){ throw new NoSuchMethodError(nosuchmethodexception.getMessage()); }catch (ClassNotFoundException classnotfoundexception){ throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
首先检查调用者的访问权限,然后尝试从缓存中检查代理类Class是否创建过,如果没有就新建一个,最后反射调用Class的构造器创建实例
java.lang.reflect.Proxy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public class Proxy implements java .io .Serializable { @CallerSensitive public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null ) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null ) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run () { cons.setAccessible(true ); return null ; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } }
2.2. CGLIB动态代理 CGLIB是Spring提供的一种动态代理创建方式,与JDK动态代理类似,它也提供了MethodInterceptor
用来定义代理行为
org.springframework.cglib.proxy.MethodInterceptor 1 2 3 public interface MethodInterceptor extends Callback { Object intercept (Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable ; }
也提供了一个工厂,给你来创建代理类
org.springframework.cglib.proxy.Enhancer 1 2 3 4 5 6 7 8 9 10 public class Enhancer extends AbstractClassGenerator { private Class superclass; private Callback[] callbacks; public Object create () ; }
不同的是CGLIB不再要求你提供目标类实现的接口了,因为它是通过继承的方式来进行代理,所以要代理的类或方法不能声明为final
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ProxyInterceptor implements MethodInterceptor { private void before (Object object, Method method, Object[] objects) { System.out.println("before " + method.getName()); } private void after (Object object, Method method, Object[] objects) { System.out.println("after " + method.getName()); } @Override public Object intercept (Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { before(object, method, args); Object result = methodProxy.invokeSuper(object, args); after(object, method, args); return result; } }
1 2 3 4 5 6 7 8 9 public class ProxyFactory { public static <T> T createProxy (Class<T> clazz) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(new ProxyInterceptor()); return (T)enhancer.create(); } }
1 2 3 4 5 6 7 8 9 public class Client { public static void main (String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/shanhuiming/" ); Handler proxy = ProxyFactory.createProxy(Handler.class ) ; proxy.handle("xxx" ); } }