JDK动态代理java
jdk自带的动态代理主要是经过实现InvocationHandler数组
InvocationHandler的主要方法缓存
Object invoke(Object proxy, Method method,Object[] args)throws Throwable安全
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。即调用真实业务的方法都会进入到此invoke方法,至于为何,稍后再说明多线程
方法详细介绍app
Method-指代具体被代理的方法。
args -包含传入代理实例上方法调用的参数,若是接口方法不使用参数,则为 null。ide
return: 从代理实例的方法调用返回的值。函数
throws: Throwable - 从代理实例上的方法调用抛出的异常。测试
少说点废话吧 ,关于什么是动态代理网上不少介绍,这里直接从源码开始。。ui
public interface HelloWorld { void say(); }
public class HelloWorldImp implements HelloWorld { @Override public void say() { System.out.println("hello world!"); } }
public class HelloProxy implements InvocationHandler { private Object target;//被代理对象 public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("berfor....."); method.invoke(target, args); System.out.println("after....."); return null; } }
public class Client { public static void main(String[] args) { HelloProxy h = new HelloProxy(); HelloWorld helloWorld = (HelloWorld) h.bind(new HelloWorldImp()); helloWorld.say(); } }
咱们利用ProxyGenerator类的generateProxyClass方法生成代理对象的class文件在idea中打开,豁然开朗其实主要一步就在于生成类的过程,类文件中创建被代理对象接口的invoke调用
String path = "D://aaa.class"; byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloWorldImp.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } }
下面直接看源码吧
public final class $Proxy0 extends Proxy implements HelloWorld { 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 say() 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", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.canyou.proxy.HelloWorld").getMethod("say"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
生成的代理对象一个有4个方法,其中就有咱们的say方法,里面调用handle的invoke方法,其余三个是全部类都有的,直接用的Method的反射机制实现的代理。
3、代理类的生成
那jdk源码是怎么生成代理类的呢?
首先看Proxy类的newProxyInstance方法吧
/** * 这里有三个参数, * 第一个是传入classloader,通常状况是传入当前的classloader. * 第二个参数表示的是接口, * 第三个是Invocationhandler */ @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); } }
而后看getProxyClass0方法
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } //从缓存中获取,若是不存在就建立 return proxyClassCache.get(loader, interfaces); }
使用proxyClassCache作缓存,其目的是为了复用,同时防止多线程重复建立
//获取或生成代理类 此处由于不是线程安全的作了屡次判断 public V get(K key, P parameter) { Objects.requireNonNull(parameter); //删除过时条目 expungeStaleEntries(); //建立cacheKey Object cacheKey = CacheKey.valueOf(key, refQueue); //查看key是否已经存在valuemaps中 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { //不存在的话经过,再次尝试尝试获取,若是没有就插入 ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } //生成代理对象的key 为弱引用类型,这里重要的subKeyFactory.apply方法 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //尝试从valuemap中获取 Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; //这个后面的逻辑基本上是若是建立已经有了 就替换或者直接添加到缓存 while (true) { if (supplier != null) { V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }
ProxyClassFactory.apply中的重要片断方法,全部代理的class对象就这么来的
/* * 这里才是重点 就像以前生成的class文件同样 * 生成代理类的字节数组 */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); }
//生成代理类 public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) { ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); /** * 生成具体文件字节数组 * 1.找到全部接口的方法 * 2.添加object类的三个方法 tostring hashcode equils * 3.遍历生成具体的代理方法,代理方法的逻辑都想似,回调咱们的代理类 */ final byte[] var4 = var3.generateClassFile(); // private static final boolean saveGeneratedFiles = GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue(); //设置sun.misc.ProxyGenerator.saveGeneratedFiles = true,就会生成代理类class的文件 if (saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { try { int var1 = var0.lastIndexOf(46); Path var2; if (var1 > 0) { //生成path 将.替换成系统文件分隔符 Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); //建立文件夹 Files.createDirectories(var3); //具体文件 var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { //没包就放在项目根目录下 var2 = Paths.get(var0 + ".class"); } //写入到文件中 Files.write(var2, var4, new OpenOption[0]); return null; } catch (IOException var4x) { throw new InternalError("I/O exception saving generated file: " + var4x); } } }); } return var4; }
之前老是知道有动态代理这么一回事,理解也不是很深,经过源代码的阅读,对JDK的动态代理实现清晰不少吧,应该对后面的Spring AOP的具体实现会更有帮助。不过里面也有不少地方没有深刻了,仍是能力不够吧,好比缓存代理,权限验证等。