JAVA动态代理模式源码解析
来源:互联网 发布:如何上淘宝一千零一夜 编辑:程序博客网 时间:2024/06/05 08:20
动态代理:代理类在运行时生成,即java在编译完之后并没有实际的class文件,而是在运行时生成类字节码,并加载到JVM中。
实现动态代理的步骤:
1、定义一个公共接口,一个目标类,目标类实现公共接口。
2、自己定义一个类,即调用处理器类,实现InvocationHandler接口,代理类调用任何方法都会经过这个调用处理类
3、生成代理对象,调用Proxy.newProxyInstance()方法,需要三个参数,分别为目标类的类加载器、实现的一系列接口和调用处理器实例。
下面写个简单的demo分析它的实现原理
//代理类和目标类的公共接口public interface TrainTicketSale { void sellTickets();}//目标类public class TrainStationSale implements TrainTicketSale { @Override public void sellTickets() { System.out.println("火车站出售火车票"); }}//处理器类public class TrainTicketHandler implements InvocationHandler{ private TrainTicketSale realSubject; public TrainTicketHandler(TrainTicketSale target){ //传入目标类对象 this.realSubject=target; } @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("--------- before---------"); //反射调用目标类方法 Object result=method.invoke(realSubject,objects); System.out.println("--------- after---------"); return result; }}//测试Testpublic class MyClassTest { public static void main(String[] args){ TrainTicketSale stationSale=new TrainStationSale(); TrainTicketHandler handler=new TrainTicketHandler(stationSale); TrainTicketSale proxy = (TrainTicketSale) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), stationSale.getClass().getInterfaces(), handler); proxy.sellTickets(); }}//控制台打印结果 com.intellij.rt.execution.application.AppMain com.example.MyClassTest--------- before---------火车站出售火车票--------- after--------
现在来分析下动态代理的执行流程
/***loader 类加载器*interfaces 目标实现接口* h 处理器实现类*/public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } /* * 获取代理类对象 */ Class<?> cl = getProxyClass0(loader, interfaces); /* * 调用代理类构造方法 */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); return newInstance(cons, h); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
再看下getProxyClass0加载类的这个方法
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { // 接口实现的方法超过最大方法数,抛出异常 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } Class<?> proxyClass = null; //收集接口名作为代理类缓存的key String[] interfaceNames = new String[interfaces.length]; // 检测重复的接口名字 Set<Class<?>> interfaceSet = new HashSet<>(); for (int i = 0; i < interfaces.length; i++) { String interfaceName = interfaces[i].getName(); Class<?> interfaceClass = null; try { //加载目标类实现接口到内存 interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException( interfaces[i] + " is not visible from class loader"); } //....省略无关紧要代码 } //将目标接口名数组作为key List<String> key = Arrays.asList(interfaceNames); /* * 使用classLoader查找或者创建代理类缓存 */ Map<List<String>, Object> cache; synchronized (loaderToCache) { cache = loaderToCache.get(loader); if (cache == null) { cache = new HashMap<>(); loaderToCache.put(loader, cache); } } synchronized (cache) { do { Object value = cache.get(key); if (value instanceof Reference) { proxyClass = (Class<?>) ((Reference) value).get(); } if (proxyClass != null) { // 缓存中已经有代理类,直接返回 return proxyClass; } else if (value == pendingGenerationMarker) { // proxy class being generated: wait for it try { cache.wait(); } catch (InterruptedException e) { /* * The class generation that we are waiting for should * take a small, bounded time, so we can safely ignore * thread interrupts here. */ } continue; } else { /* * No proxy class for this list of interfaces has been * generated or is being generated, so we will go and * generate it now. Mark it as pending generation. */ cache.put(key, pendingGenerationMarker); break; } } while (true); } synchronized (nextUniqueNumberLock) { num = nextUniqueNumber++; } String proxyName = proxyPkg + proxyClassNamePrefix + num; //关键代码,调用底层的native方法生成代理类 proxyClass = generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray); } // add to set of all generated proxy classes, for isProxyClass proxyClasses.put(proxyClass, null); } finally { //生成之后通过弱引用保存到cache中 synchronized (cache) { if (proxyClass != null) { cache.put(key, new WeakReference<Class<?>>(proxyClass)); } else { cache.remove(key); } cache.notifyAll(); } } return proxyClass; }
底层生成代理类后,再调用它的newInstance()方法
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()); } } }
构造方法传入InvocationHandler的实现类对象,那么这个handler对象传进去到底是干嘛使的呢?我们可以看下系统帮我们生成的代理类是什么样子的,我们用反编译工具打开硬盘中的代理类。
import com.example.TrainTicketSale; import java.lang.reflect.*; public final class $Proxy11 extends Proxy implements TrainTicketSale { // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例 public $Proxy11(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 sellTickets() { try { // 实际上就是调用TrainTicketHandler的public Object invoke(Object proxy, Method method, Object[] args)方法 super.h.invoke(this, m3, null); 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); } } public final String toString() { try { return (String)super.h.invoke(this, m2, null); } catch(Error _ex) { } catch(Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } private static Method m1; private static Method m3; private static Method m0; private static Method m2; // 在静态代码块中获取了4个方法:Object中的equals方法、TrainTicketSale中的sellTickets方法、Object中的hashCode方法、Object中toString方法 static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("com.example.TrainTicketSale").getMethod("sellTickets", 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]); } catch(NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch(ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
可以看出,代理类实现了目标类的接口,并保存了接口中每个Method对象,当代理类调用接口方法时,都会调用到h.invoke()方法。
参考链接:
代理模式及Java实现动态代理
JDK动态代理实现原理
阅读全文
0 0
- JAVA动态代理模式源码解析
- Java--JDK动态代理核心源码解析
- 动态代理源码解析
- 深度解析JAVA动态代理设计模式
- 深度解析JAVA动态代理设计模式
- JDK动态代理源码解析
- Retrofit源码解析-动态代理
- Retrofit源码解析-动态代理
- jdk动态代理源码解析
- java动态代理解析
- Java动态代理解析
- Java动态代理解析
- Java动态代理解析
- Java动态代理解析
- java动态代理Proxy源码解析(Jdk 1.6)
- 开源项目源码解析-Java 动态代理
- java动态代理和com.sun.proxy.$Proxy0源码解析
- Hadoop源码解析之java动态代理机制
- vue keep-alive的作用
- Dividing HDU
- 指向类成员函数的指针
- EmguCV Mat元素访问的方法——加强方法
- Linux查找含有某字符串的所有文件
- JAVA动态代理模式源码解析
- 深刻理解HDFS工作机制
- Mysql外键级联动作(删除和更新)
- 作业
- 定义一个图形类及其子类(三角形类和矩形类),分别计算其面积和周长
- angularjs的音乐循环播放
- 汇编(五)
- LeetCode--Decode Ways(解码方式)Python
- SqlServer从备份中还原