java动态代理就是动态的为委托类生成代理类,相比静态代理需要预先编写代理类源码,动态代理只需要定义好接口,然后使用反射动态生成指定接口的实现类(代理类)。以下通过一个demo来分析动态代理的实现细节。
步骤1:定义接口并提供接口实现类。
/** * 打电话服务接口 */ interface CallService{ public void call(); } /** * 发信息服务接口 */ interface SendMessageService{ public void sendMessage(); } /** * 手机服务接口 */ interface PhoneService extends CallService, SendMessageService{ } /** * 服务实现类 */ class PhoneServiceImpl implements PhoneService{ @Override public void call() { System.out.println("call----"); } @Override public void sendMessage() { System.out.println("sendMessage----"); } }
步骤2:为接口实现类提供代理。
/** * 代理逻辑 */ class ServiceHandler implements InvocationHandler{ /** * 被代理对象 */ private PhoneService target; public ServiceHandler(PhoneService target){ this.target = target; } /** * 提供需要被代理执行的逻辑 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log("begin servie----"); Object rtn = method.invoke(target, args); log("finish servie----"); return rtn; } private void log(String info){ System.out.println(new Date() + " : " + info); } }
以上两步已经准备好了接口和代理逻辑,接下来就测试代理的执行结果。
public class Demo { public static void main(String[] args) throws Exception { //创建被代理的对象 PhoneService target = new PhoneServiceImpl(); ServiceHandler serviceHandler = new ServiceHandler(target); //创建代理对象 PhoneService proxy = (PhoneService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), serviceHandler); //通过代理执行业务逻辑 proxy.call(); proxy.sendMessage(); } }
以上测试代码的执行结果如下:
Thu Mar 27 21:40:21 CST 2014 : begin servie---- call---- Thu Mar 27 21:40:21 CST 2014 : finish servie---- Thu Mar 27 21:40:21 CST 2014 : begin servie---- sendMessage---- Thu Mar 27 21:40:21 CST 2014 : finish servie----
Demo1演示了为PhoneServiceImpl 提供动态代理类来打印日志服务,涉及到的相关类的关系如下:
InvocationHandler接口定义了invoke(Object proxy, Method method, Object[] args)方法,用户必须实现InvocationHandler接口,实现invoke 方法来提供代理类的处理逻辑。
Proxy类是所有动态生成的代理类的父类,它提供了为接口动态生成代理类及其对象的方法。通过调用Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)为指定接口interfaces生成名为$ProxyN(N由Proxy的计数器确定)的实现类,该实现类中实现了所有接口定义的方法,方法内部实际是对父类Proxy的InvocationHandler 类型成员h调用invoke方法,Proxy相关源代码如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{ if (h == null) { throw new NullPointerException(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } /* * Look up or generate the designated proxy class. */ //为所有的接口生成一个实现类,并加载生成Class 对象cl Class<?> cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { //通过反射获取cl的构造方法,并传入h 构造出代理类实例 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } } private static Object newInstance(Constructor<?> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString()); } } }
跟踪Proxy源码,获取器动态生成的字节码并将其保存到.class文件,然后用jd-gui 反编译字节码文件可得到如下动态代理类代码:
package com.hsh.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements PhoneService { private static Method m4; private static Method m1; private static Method m3; private static Method m0; private static Method m2; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final void sendMessage() throws { try { this.h.invoke(this, m4, null); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final void call() throws { try { this.h.invoke(this, m3, null); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } static { try { m4 = Class.forName("com.hsh.dynamicproxy.PhoneService").getMethod("sendMessage", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.hsh.dynamicproxy.PhoneService").getMethod("call", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { } throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } }
通过看生成的代理类源码,代理的原理就一目了然了。