Java动态代理初探
说明:
本文尝试探讨JDK1.7的Java动态代理内部执行原理,由于本人水平有限,不对之处还望指正!
一、场景说明
需要对某些方法的性能进行监控,主要监控方法的执行时间,为此采用Java动态代理实现。
二、代码实例
2.1 业务接口
/** * 计算数字接口 * * @since 2016-08-19 * */ public interface CountNumberService { /** * 计算1到max相加的值 * * @param max 最大数字 * @return int(1到max相加的值) */ public int countOneToHundredAdd(int max); /** * 计算1到max相乘的值 * * @param max 最大数字 * @return int(1到max相乘的值) * */ public int countOneToHundredMultiply(int max); }
2.2 业务接口实现类
/** * 计算数字接口默认实现 * * @since 2016-08-19 * */ public class DefaultCountNumberServiceImpl implements CountNumberService { public int countOneToHundredAdd(int max) { int count = 0; for(int i = 1;i <= max;i++){ count += i; } return count; } public int countOneToHundredMultiply(int max) { int count = 1; for(int i = 1;i <= max;i++){ count = count * i; } try { //人为的增加该方法执行时间 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return count; } }
2.3 动态代理类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CountNumberProxy implements InvocationHandler { private Object target; public CountNumberProxy(Object target){ this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //开始时间 long startTime = System.currentTimeMillis(); Object result = method.invoke(target, args); //结束时间 long endTime = System.currentTimeMillis(); System.out.println("该方法【" + method.getName() + "】执行时间为:" + (endTime - startTime)); return result; } /** * 获取目标对象target的代理类 * * @return object 目标对象target代理类 */ public Object getProxy(){ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } }
2.4 测试
public class Test { public static void main(String[] args) { //目标对象 CountNumberService countNumberService = new DefaultCountNumberServiceImpl(); //构造动态代理类 CountNumberProxy proxy = new CountNumberProxy(countNumberService); //获取代理对象 countNumberService = (CountNumberService) proxy.getProxy(); int max = 10; System.out.println("1到" + max + "相加的值为:" + countNumberService.countOneToHundredAdd(max)); System.out.println("1到" + max +"相乘的值为:" + countNumberService.countOneToHundredMultiply(max)); } } 执行结果: 该方法【countOneToHundredAdd】执行时间为:0 1到10相加的值为:55 该方法【countOneToHundredMultiply】执行时间为:2012 1到10相乘的值为:3628800
2.5 总结
通过Java的动态代理,实现了对方法的性能监控,统计出了方法的执行时间。从代码实例可以看出,要想实现Java动态代理,需要实现InvocationHandler接口,重写invoke(...)方法,通过Proxy.newProxyInstance(...)方法获得代理类。然而,Java内部是如何执行动态代理,下面进行初步探讨。
三、Java动态代理内部实现
3.1 InvocationHandler接口
InvocationHandler接口,只有一个方法:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable。该方法是真正执行监控性能的地方。
参数说明:
proxy - 实现InvocationHandler接口的动态代理类中目标对象的代理类,该类由Java动态代理内部自动生成并传入
method -目标对象中的方法,Java动态代理内部通过方法获得并传入。
例如:m3 = Class.forName("com.proxy.two.service.CountNumberService").getMethod("countOneToHundredAdd", new Class[] { Integer.TYPE });
m3即为反射获取的method。
args - method方法参数的入参,该参数由proxy代理类对于method方法入参传入。
3.2 Proxy类
该类是Java动态代理获取目标对象代理类的超类,该类提供了获取目标对象代理类实例的静态方法。
Proxy类主要关注两个方法,一个属性。
/** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h;
说明:
该属性是实现InvocationHandler接口的动态代理类,3.1中invoke(...)方法的调用就是通过:this.h.invoke(...)来调用的,而this就是该属性引用的动态代理类。
/** * Constructs a new {@code Proxy} instance from a subclass * (typically, a dynamic proxy class) with the specified value * for its invocation handler. * * @param h the invocation handler for this proxy instance */ protected Proxy(InvocationHandler h) { doNewInstanceCheck(); this.h = h; }
说明:
该带参构造函数目的是:实例化目标对象代理类。
说明:
下面该方法是实例化目标对象代理类,通过该方法就能获取目标对象代理类实例
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { 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()); } }
3.3 使用ProxyGenerator.generateProxyClass(...)
使用ProxyGenerator.generateProxyClass(...)方法能获取代理类class字节数组,通过FileOutputStream写入class字节数组获取代理类class文件。
代码实例目标对象代理类class文件内容如下:
import com.proxy.two.service.CountNumberService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class proxy89 extends Proxy implements CountNumberService { private static Method m1; private static Method m4; private static Method m0; private static Method m3; private static Method m2; public proxy89(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int countOneToHundredMultiply(int paramInt) throws { try { return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int countOneToHundredAdd(int paramInt) throws { try { return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m4 = Class.forName("com.proxy.two.service.CountNumberService").getMethod("countOneToHundredMultiply", new Class[] { Integer.TYPE }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("com.proxy.two.service.CountNumberService").getMethod("countOneToHundredAdd", new Class[] { Integer.TYPE }); 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()); } } }
从上可以看出:public final class proxy89 extends Proxy implements CountNumberService,目标对象代理类继承了Proxy超类,实现了目标对象实现的接口CountNumberService。这也说明了为什么Java动态代理需要接口的原因。
3.4 使用ProxyGenerator.generateProxyClass(...)实例
import java.io.FileOutputStream; import java.io.IOException; import sun.misc.ProxyGenerator; public class ProxyClassUtil { @SuppressWarnings("restriction") public static void generateProxyClassToPath(String path,String proxyName,Class<?>[] interfaces){ byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); FileOutputStream out = null; try{ out = new FileOutputStream(path); out.write(proxyClassFile); out.flush(); }catch(Exception e){ e.printStackTrace(); }finally{ if(null != out){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
public class Test { public static void main(String[] args) { //目标对象 CountNumberService countNumberService = new DefaultCountNumberServiceImpl(); //构造代理类 CountNumberProxy proxy = new CountNumberProxy(countNumberService); //获取代理 countNumberService = (CountNumberService) proxy.getProxy(); int max = 10; System.out.println("1到" + max + "相加的值为:" + countNumberService.countOneToHundredAdd(max)); System.out.println("1到" + max +"相乘的值为:" + countNumberService.countOneToHundredMultiply(max));
//生成目标对象代理类class文件 ProxyClassUtil.generateProxyClassToPath("d://proxy89.class", "proxy89", DefaultCountNumberServiceImpl.class.getInterfaces()); } }