Java反射
java反射中的Proxy类的方法getProxyClass中的一个参数,我们可以看到源码如下
package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
该方法中的参数proxy是生成的代理类对象,method是被代理类的某个方法,args是在该method中的参数。业务增强就是在这里
一个次动态代理的组成,一个接口,一个实现类,一个动态代理类。这个动态代理类是生成的,并且该类继承了Proxy并实现了接口。因为已经继承了Proxy所以被代理类一定需要一个接口,而不能是个抽象类。这个接口存在是为了提供给动态生成的代理类,需要实现哪些方法,方法的修饰符和参数类型都是什么。
一个完整的例子如下。
package com.easyjdbc.proxyobtain; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Dao { void save(String name); void put(); } class DaoImpl implements Dao { @Override public void save(String name) { System.out.println("save..."+name); } @Override public void put() { System.out.println("put"); } } public class DynamicProxyTest { public static void main(String[] args) throws Exception { Object target = new DaoImpl(); Class<?> proxyClass = Proxy.getProxyClass(DaoImpl.class.getClassLoader(), DaoImpl.class.getInterfaces()); InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("before..."); result = method.invoke(target, args); System.out.println("after..."); return result; } }; Dao userDao = (Dao) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler); userDao.save("123"); } }
其中最为重要的方法就是public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException。可以进去看到于源码有安全检查和数据
接着点进入,注意这里都是点方法,不是点类
看到,apply就是生成代理类得函数。接着点进去,在实现类中找到
然后到
其中proxyName就是代理类得类名,porxyPkg是$Proxy所以代理类就是$Proxy0,$Proxy1这样得类名,往下翻是生成字节码得方法,其中生成字节码得方法不让看,安全问题而放在了一个安全得包中。但是我们将生成得字节码从内容中读出并放在文件中。反编译后如下。
import com.easyjdbc.proxyobtain.Dao; 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 Dao { private static Method m1; private static Method m3; private static Method m4; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { 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 void put() { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void save(String paramString) { try { this.h.invoke(this, m4, new Object[] { paramString }); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } 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") }); m3 = Class.forName("com.easyjdbc.proxyobtain.Dao").getMethod("put", new Class[0]); m4 = Class.forName("com.easyjdbc.proxyobtain.Dao").getMethod("save", new Class[] { Class.forName("java.lang.String") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
生成得代理类可以看出,构造方法传入一个InvocationHandler得实例,被代理得类中得方法与代理类得方法一一对应,而每个方法的方法体都是在调用传入参数InvocationHandler实例的invoke方法。三个参数一次对应为代理类this,被代理类的方法method,该方法的参数args。这样被代理类的每个方法都得到了增强。
在获取生成代理类的时ProxyGenerator不让用,右键项目、Properties、javaBuildPath、Library中、JRE systemLibrary、Edit、改为workspace default JRE或者改为Alternative JRE
上面创建代理类的过程还可以直接一步完成
Dao proxyClass = (Dao) Proxy.newProxyInstance(DaoImpl.class.getClassLoader(), DaoImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("before..."); result = method.invoke(target, args); System.out.println("after..."); return result; } });
内部也是和前面方法的调用时一样的