欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > DOCX文档下载  

    Java JDK 动态代理使用及实现原理分析.docx

    • 资源ID:3159499       资源大小:45.62KB        全文页数:27页
    • 资源格式: DOCX        下载积分:6.99金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要6.99金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Java JDK 动态代理使用及实现原理分析.docx

    Java JDK 动态代理使用及实现原理分析Java JDK 动态代理使用及实现原理分析 一、什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。 代理模式UML图: 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。 二、Java 动态代理类 Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: (1)Interface InvocationHandler:该接口中仅定义了一个方法 java view plain copy 在CODE上查看代码片派生到我的代码片 publicobject invoke(Object obj,Method method, Object args) 在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request,args为该方法的参数数组。这个抽象方法在代理类中动态实现。 (2)Proxy:该类即为动态代理类,其中主要包含以下内容: protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。 static Class getProxyClass (ClassLoaderloader, Class interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。 static Object newProxyInstance(ClassLoaderloader, Class interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法) 所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。 在使用动态代理类时,我们必须实现InvocationHandler接口 通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。 动态代理步骤: 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法 2.创建被代理的类以及接口 3.通过Proxy的静态方法 newProxyInstance(ClassLoaderloader, Class interfaces, InvocationHandler h)创建一个代理 4.通过代理调用方法 三、JDK的动态代理怎么使用? 1、需要动态代理的接口: java view plain copy 在CODE上查看代码片派生到我的代码片 package jiankunking; /* * 需要动态代理的接口 */ public interface Subject /* * 你好 * * param name * return */ public String SayHello(String name); /* * 再见 * * return */ public String SayGoodBye; 2、需要代理的实际对象 java view plain copy 在CODE上查看代码片派生到我的代码片 package jiankunking; /* * 实际对象 */ public class RealSubject implements Subject /* * 你好 * * param name * return */ public String SayHello(String name) return "hello " + name; /* * 再见 * * return */ public String SayGoodBye return " good bye " 3、调用处理器实现类 java view plain copy 在CODE上查看代码片派生到我的代码片 package jiankunking; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /* * 调用处理器实现类 * 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象 */ public class InvocationHandlerImpl implements InvocationHandler /* * 这个就是我们要代理的真实对象 */ private Object subject; /* * 构造方法,给我们要代理的真实对象赋初值 * * param subject */ public InvocationHandlerImpl(Object subject) this.subject = subject; /* * 该方法负责集中处理动态代理类上的所有方法调用。 * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 * * param proxy 代理类实例 * param method 被调用的方法对象 * param args 调用参数 * return * throws Throwable */ public Object invoke(Object proxy, Method method, Object args) throws Throwable /在代理真实对象前我们可以添加一些自己的操作 System.out.println("在调用之前,我要干点啥呢?"); System.out.println("Method:" + method); /当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 Object returnValue = method.invoke(subject, args); /在代理真实对象后我们也可以添加一些自己的操作 System.out.println("在调用之后,我要干点啥呢?"); return returnValue; 4、测试 java view plain copy 在CODE上查看代码片派生到我的代码片 package jiankunking; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /* * 动态代理演示 */ public class DynamicProxyDemonstration public static void main(String args) /代理的真实对象 Subject realSubject = new RealSubject; /* * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 */ InvocationHandler handler = new InvocationHandlerImpl(realSubject); ClassLoader loader = handler.getClass.getClassLoader; Class interfaces = realSubject.getClass.getInterfaces; /* * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 */ Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); System.out.println("动态代理对象的类型:"+subject.getClass.getName); String hello = subject.SayHello("jiankunking"); System.out.println(hello); / String goodbye = subject.SayGoodBye; / System.out.println(goodbye); 5、输出结果如下: 四、动态代理怎么实现的? 从使用代码中可以看出,关键点在: java view plain copy 在CODE上查看代码片派生到我的代码片 Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); 通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。 也就是说,当代码执行到: subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢? =横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论= 以下代码来自:JDK1.8.0_92 既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么? java view plain copy 在CODE上查看代码片派生到我的代码片 public static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandler h) throws IllegalArgumentException /检查h 不为空,否则抛异常 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; ); /生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法 return cons.newInstance(new Objecth); 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方法看一下: java view plain copy 在CODE上查看代码片派生到我的代码片 /* * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>. interfaces) if (interfaces.length > 65535) throw new IllegalArgumentException("interface limit exceeded"); / If the proxy class defined by the given loader implementing / the given interfaces exists, this will simply return the cached copy; / otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); 真相还是没有来到,继续,看一下proxyClassCache java view plain copy 在CODE上查看代码片派生到我的代码片 /* * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>, Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory, new ProxyClassFactory); 奥,原来用了一下缓存啊 那么它对应的get方法啥样呢? java view plain copy 在CODE上查看代码片派生到我的代码片 /* * Look-up the value through the cache. This always evaluates the * code subKeyFactory function and optionally evaluates * code valueFactory function if there is no entry in the cache for given * pair of (key, subKey) or the entry has already been cleared. * * param key possibly null key * param parameter parameter used together with key to create sub-key and * value (should not be null) * return the cached value (never null) * throws NullPointerException if code parameter passed in or * code sub-key calculated by * code subKeyFactory or code value * calculated by code valueFactory is null. */ public V get(K key, P parameter) Objects.requireNonNull(parameter); expungeStaleEntries; Object cacheKey = CacheKey.valueOf(key, refQueue); / lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap = null) /putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入 ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>); if (oldValuesMap != null) valuesMap = oldValuesMap; / create subKey and retrieve the possible Supplier<V> stored by that / subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) if (supplier != null) / supplier might be a Factory or a CacheValue<V> instance 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); 我们可以看到它调用了 supplier.get; 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。 来瞅瞅,get里面又做了什么? java view plain copy 在CODE上查看代码片派生到我的代码片 public synchronized V get / serialize access / re-check Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) / something changed while we were waiting: / might be that we were replaced by a CacheValue / or were removed because of failure -> / return null to signal WeakCache.get to retry / the loop return null; / else still us (supplier = this) / create new value V value = null; try value = Objects.requireNonNull(valueFactory.apply(key, parameter); finally if (value = null) / remove us on failure valuesMap.remove(subKey, this); / the only path to reach here is with non-null value assert value != null; / wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); / try replacing us with CacheValue (this should always succeed) if (valuesMap.replace(subKey, this, cacheValue) / put also in reverseMap reverseMap.put(cacheValue, Boolean.TRUE); else throw new AssertionError("Should not reach here"); / successfully replaced us with new CacheValue -> return the value / wrapped by it return value; 发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法: java view plain copy 在CODE上查看代码片派生到我的代码片 /* * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>, Class<?>> / prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy" / next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong; Override public Class<?> apply(ClassLoader loader, Class<?> interfaces) Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try interfaceCla

    注意事项

    本文(Java JDK 动态代理使用及实现原理分析.docx)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开