动态代理模式--源码分析

Proxy源码

1,成员变量

?代理类的构造函数参数。默认每个代理类都具有一个invocationHandler的构造方法。(本文代码主要基于jdk 1.7)

  1. /** parameter types of a proxy class constructor */
  2. private static final Class<?>[] constructorParams =
  3. { InvocationHandler.class };

?缓存代理对象。

  1. private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
  2. proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

代理对象的InvacationHandler,每个代理对象都有一个与之对应的Invocationhandler对象。

  1. /**
  2. * the invocation handler for this proxy instance.
  3. * @serial
  4. */
  5. protected InvocationHandler h;

2,构造方法

?私有构造方法,禁止外部直接通过new关键字生成代理对象。

  1. /**
  2. * Prohibits instantiation.
  3. */
  4. private Proxy() {
  5. }

protected构造函数。

  1. /**
  2. * Constructs a new {@code Proxy} instance from a subclass
  3. * (typically, a dynamic proxy class) with the specified value
  4. * for its invocation handler.
  5. *
  6. * @param h the invocation handler for this proxy instance
  7. */
  8. protected Proxy(InvocationHandler h) {
  9. doNewInstanceCheck();
  10. this.h = h;
  11. }

3,newProxyInstance方法

?newProxyInstance方法是我们外部生成代理对象时候主要调用的方法。

  1. @CallerSensitive
  2. public static Object newProxyInstance(ClassLoader loader,
  3. Class<?>[] interfaces,
  4. InvocationHandler h)
  5. throws IllegalArgumentException
  6. {
  7. if (h == null) {//检查InvocationHandler,如果为空,直接抛出异常
  8. throw new NullPointerException();
  9. }
  10. final Class<?>[] intfs = interfaces.clone();
  11. final SecurityManager sm = System.getSecurityManager();
  12. if (sm != null) {
  13. //检查对应的classLoader是否为空,以及接口是否可见
  14. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  15. }
  16. /*
  17. * Look up or generate the designated proxy class.
  18. */
  19. Class<?> cl = getProxyClass0(loader, intfs);
  20. /*
  21. * Invoke its constructor with the designated invocation handler.
  22. */
  23. try {
  24. final Constructor<?> cons = cl.getConstructor(constructorParams);
  25. final InvocationHandler ih = h;
  26. if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
  27. // create proxy instance with doPrivilege as the proxy class may
  28. // implement non-public interfaces that requires a special permission
  29. return AccessController.doPrivileged(new PrivilegedAction<Object>() {
  30. public Object run() {
  31. return newInstance(cons, ih);
  32. }
  33. });
  34. } else {
  35. return newInstance(cons, ih);
  36. }
  37. } catch (NoSuchMethodException e) {
  38. throw new InternalError(e.toString());
  39. }
  40. }

我们可以看到,最主要的方法在getProxyClass0方法,我们查看其对应的方法。

  1. private static Class<?> getProxyClass0(ClassLoader loader,
  2. Class<?>... interfaces) {
  3. if (interfaces.length > 65535) {
  4. throw new IllegalArgumentException("interface limit exceeded");
  5. }
  6. // If the proxy class defined by the given loader implementing
  7. // the given interfaces exists, this will simply return the cached copy;
  8. // otherwise, it will create the proxy class via the ProxyClassFactory
  9. return proxyClassCache.get(loader, interfaces);
  10. }

我们从代码注释中可以看到,此出主要出缓存中获取代理对象。缓存表中主要存放以类加载器为key的Map对象。我们查看缓存的proxyClassCache的get方法。

  1. public V get(K key, P parameter) {
  2. Objects.requireNonNull(parameter);//校验接口不为空
  3. expungeStaleEntries();
  4. Object cacheKey = CacheKey.valueOf(key, refQueue);//生成缓存对象
  5. // lazily install the 2nd level valuesMap for the particular cacheKey
  6. //内部缓存map中获取对应的对象
  7. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  8. if (valuesMap == null) {//为空
  9. ConcurrentMap<Object, Supplier<V>> oldValuesMap
  10. = map.putIfAbsent(cacheKey,
  11. valuesMap = new ConcurrentHashMap<>());//map中存入对应cacheKey和Map
  12. if (oldValuesMap != null) {
  13. valuesMap = oldValuesMap;
  14. }
  15. }
  16. // create subKey and retrieve the possible Supplier<V> stored by that
  17. // subKey from valuesMap
  18. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  19. Supplier<V> supplier = valuesMap.get(subKey);
  20. Factory factory = null;
  21. while (true) {
  22. if (supplier != null) {
  23. // supplier might be a Factory or a CacheValue<V> instance
  24. V value = supplier.get();//Supplier实现了一个get接口。主要由Factory实现其具体接口。
  25. if (value != null) {
  26. return value;//存在,则直接返回
  27. }
  28. }
  29. // else no supplier in cache
  30. // or a supplier that returned null (could be a cleared CacheValue
  31. // or a Factory that wasn‘t successful in installing the CacheValue)
  32. // lazily construct a Factory
  33. if (factory == null) {
  34. factory = new Factory(key, parameter, subKey, valuesMap);//创建Factory
  35. }
  36. if (supplier == null) {//Supplier
  37. supplier = valuesMap.putIfAbsent(subKey, factory);
  38. if (supplier == null) {
  39. // successfully installed Factory
  40. supplier = factory;
  41. }
  42. // else retry with winning supplier
  43. } else {
  44. if (valuesMap.replace(subKey, supplier, factory)) {
  45. // successfully replaced
  46. // cleared CacheEntry / unsuccessful Factory
  47. // with our Factory
  48. supplier = factory;
  49. } else {
  50. // retry with current supplier
  51. supplier = valuesMap.get(subKey);
  52. }
  53. }
  54. }
  55. }

此处主要用到了ConcurrentHashMap的相关操作。

我们主要的操作都是通过自定义的Factory的get方法来获取我们对应的缓存对象。

  1. private final class Factory implements Supplier<V> {
  2. private final K key;
  3. private final P parameter;
  4. private final Object subKey;
  5. private final ConcurrentMap<Object, Supplier<V>> valuesMap;
  6. Factory(K key, P parameter, Object subKey,
  7. ConcurrentMap<Object, Supplier<V>> valuesMap) {
  8. this.key = key;
  9. this.parameter = parameter;
  10. this.subKey = subKey;
  11. this.valuesMap = valuesMap;
  12. }
  13. @Override
  14. public synchronized V get() { // serialize access
  15. // re-check
  16. Supplier<V> supplier = valuesMap.get(subKey);
  17. if (supplier != this) {
  18. // something changed while we were waiting:
  19. // might be that we were replaced by a CacheValue
  20. // or were removed because of failure ->
  21. // return null to signal WeakCache.get() to retry
  22. // the loop
  23. return null;
  24. }
  25. // else still us (supplier == this)
  26. // create new value
  27. V value = null;
  28. try {
  29. value = Objects.requireNonNull(valueFactory.apply(key, parameter));
  30. } finally {
  31. if (value == null) { // remove us on failure
  32. valuesMap.remove(subKey, this);
  33. }
  34. }
  35. // the only path to reach here is with non-null value
  36. assert value != null;
  37. // wrap value with CacheValue (WeakReference)
  38. CacheValue<V> cacheValue = new CacheValue<>(value);
  39. // try replacing us with CacheValue (this should always succeed)
  40. if (valuesMap.replace(subKey, this, cacheValue)) {
  41. // put also in reverseMap
  42. reverseMap.put(cacheValue, Boolean.TRUE);
  43. } else {
  44. throw new AssertionError("Should not reach here");
  45. }
  46. // successfully replaced us with new CacheValue -> return the value
  47. // wrapped by it
  48. return value;
  49. }
  50. }

在此处,通过valueFactory的apply方法来生成一个新的代理对象,然后放入缓存。valueFactory为BiFunction接口实例,主要实现有KeyFactory和ProxyClassFactory。ProxyClassFactory是生成代理对象的关键。

  1. /**
  2. * A factory function that generates, defines and returns the proxy class given
  3. * the ClassLoader and array of interfaces.
  4. */
  5. private static final class ProxyClassFactory
  6. implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  7. {
  8. // prefix for all proxy class names
  9. private static final String proxyClassNamePrefix = "$Proxy";//代理名称前缀
  10. // next number to use for generation of unique proxy class names
  11. private static final AtomicLong nextUniqueNumber = new AtomicLong();//代理名称的下一个名字
  12. @Override
  13. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  14. //循环检查接口
  15. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  16. for (Class<?> intf : interfaces) {
  17. /*
  18. * Verify that the class loader resolves the name of this
  19. * interface to the same Class object.
  20. */
  21. Class<?> interfaceClass = null;
  22. try {
  23. interfaceClass = Class.forName(intf.getName(), false, loader);
  24. } catch (ClassNotFoundException e) {
  25. }
  26. if (interfaceClass != intf) {
  27. throw new IllegalArgumentException(
  28. intf + " is not visible from class loader");
  29. }
  30. /*
  31. * Verify that the Class object actually represents an
  32. * interface.
  33. */
  34. if (!interfaceClass.isInterface()) {
  35. throw new IllegalArgumentException(
  36. interfaceClass.getName() + " is not an interface");
  37. }
  38. /*
  39. * Verify that this interface is not a duplicate.
  40. */
  41. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  42. throw new IllegalArgumentException(
  43. "repeated interface: " + interfaceClass.getName());
  44. }
  45. }
  46. String proxyPkg = null; // package to define proxy class in
  47. /*
  48. * Record the package of a non-public proxy interface so that the
  49. * proxy class will be defined in the same package. Verify that
  50. * all non-public proxy interfaces are in the same package.
  51. */
  52. for (Class<?> intf : interfaces) {
  53. int flags = intf.getModifiers();
  54. if (!Modifier.isPublic(flags)) {
  55. String name = intf.getName();
  56. int n = name.lastIndexOf(‘.‘);
  57. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  58. if (proxyPkg == null) {
  59. proxyPkg = pkg;
  60. } else if (!pkg.equals(proxyPkg)) {
  61. throw new IllegalArgumentException(
  62. "non-public interfaces from different packages");
  63. }
  64. }
  65. }
  66. if (proxyPkg == null) {
  67. // if no non-public proxy interfaces, use com.sun.proxy package
  68. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  69. }
  70. /*
  71. * Choose a name for the proxy class to generate.
  72. */
  73. long num = nextUniqueNumber.getAndIncrement();
  74. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  75. /*
  76. * Generate the specified proxy class.
  77. */
  78. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  79. proxyName, interfaces);//生成最终的代理对象
  80. try {
  81. return defineClass0(loader, proxyName,
  82. proxyClassFile, 0, proxyClassFile.length);
  83. } catch (ClassFormatError e) {
  84. /*
  85. * A ClassFormatError here means that (barring bugs in the
  86. * proxy class generation code) there was some other
  87. * invalid aspect of the arguments supplied to the proxy
  88. * class creation (such as virtual machine limitations
  89. * exceeded).
  90. */
  91. throw new IllegalArgumentException(e.toString());
  92. }
  93. }
  94. }

最终的代理对象由ProxyGenerator.generateProxyClass实现。改类的源码SUN并未提供,只能尝试一些反编译技术查看,在此省略。

以上即为JDK实现动态代理的基本原理。我们抛开各种技术细节总结,可以整体的将实现过程概括为下面:

?1)检查内部缓存代码是否存在对应ClassLoader对应的代理对象。存在则直接返回,否则生成。

?2)生成代理对象时,获取对应的Factory视力,如果存在Factory实例,则直接调用其get方法,否则生成Factory实例。

?3)调用Factory的get方法,再调用ProxyClassFactory的apply方法,apply方法调用ProxyGenerator.generateProxyClass方法生成最终的代理对象。在Fatory内部,生成代理对象后,缓存代理对象。

实现自己的Proxy类

看了如上JDK Proxy类的实现,整体结构我们可以有个较为清晰的认识。但是对具体生成代理对象,以为SUN隐藏了内部实现,我们可能较为模糊,下面我们可以自己使用反射来完成一个自己的Proxy类。

个人认为,Proxy内的内部,只是将我们的接口,以及InvocationHandler方法进行组装而已。

?此部分代码参考博客:http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/

?

  1. package com.jing.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. /**
  5. * 自定义代理,实现对实例进行代理
  6. *
  7. * @author jinglongjun
  8. *
  9. * @param <T>
  10. */
  11. public final class MyProxy {
  12. private InvocationHandler handler;// 处理器
  13. /**
  14. * 禁止外部访问
  15. */
  16. private MyProxy() {
  17. }
  18. public MyProxy(InvocationHandler handler) {
  19. this.handler = handler;
  20. }
  21. /**
  22. * 代理执行方法
  23. *
  24. * @param methodName
  25. * 代理方法名称
  26. * @param obj
  27. * 目标对象
  28. * @param args
  29. * 方法执行参数
  30. * @param parameterTypes
  31. * 方法参数类型数组
  32. * @return 方法执行返回值
  33. * @throws Exception
  34. */
  35. public Object invoke(String methodName, Object obj,
  36. Class<?>[] parameterTypes, Object... args) throws Exception {
  37. if (obj == null)
  38. throw new NullPointerException("目标对象不能为空!");
  39. // 1,获取代理对象方法
  40. Method method = obj.getClass().getMethod(methodName, parameterTypes);// 获取方法
  41. // 2.获取InvocationHandler的invke方法,并执行。此处传入了目标对象的Method对象
  42. Object result = null;
  43. try {
  44. //执行Handler的Invoke方法
  45. result = handler.invoke(this, method, args);
  46. } catch (Throwable e) {
  47. e.printStackTrace();
  48. }
  49. return result;
  50. }
  51. }

调用实例

  1. package com.jing.proxy;
  2. public class TestMyProxy {
  3. public static void main(String[] args) throws Exception {
  4. HelloSubject helloSubject = new HelloSubject();
  5. SubHandler subHandler = new SubHandler(helloSubject);
  6. MyProxy proxy = new MyProxy(subHandler);
  7. Object result = proxy.invoke("doSomething", helloSubject, null, new Object[]{});
  8. System.out.println(result);
  9. }
  10. }

如上,即为整体JDK动态代理的实现,部分代码我写的比较模糊,比如缓存的具体实现步骤,此处可以在后续有时间再深入地学习,毕竟不能一口吃成胖子,还是要循环渐进。

我们通过对源码的分析很容易帮助我们更好的理解动态代理模式。

了解了动态代理的实现原理,后续我们可以分析开源框架中对动态代理模式的应用。

具体后续会根据Spring AOP的代码实现来查看动态代理对框架的作用。

?

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 21:28:33

动态代理模式--源码分析的相关文章

Java设计模式-代理模式之动态代理(附源码分析)

Java设计模式-代理模式之动态代理(附源码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的区别就是:动态代理是在运行时刻动态的创建出代理类及其对象.上篇中的静态代理是在编译的时候就确定了代理类具体类型,如果有多个类需要代理,那么就得创建多个.还有一点,如果Subject中新增了一个方法,那么对应的实现接口的类中也要相应的实习该方法,不符合设计模式原则. 动态代理的做法:在运行时刻,可以动态创建出一个实现了多个接口的代理类.每个代理类的对象都会关联一个表示内部处理

高仿JDK动态代理 底层源码实现

动态代理实现思路 实现功能:通过Proxy.newProxyInstance返回代理对象 1.创建一个处理业务逻辑的接口,我们也和JDK一样,都使用InvocationHandler作为接口名,然后接口里面一个invoke方法,jdk呢是有三个参数,我们简化了一下就只要两个参数即可. 2.声明一段java代码字符串(动态产生代理类) 3.使用IO创建代理类的java文件,将java代码字符串写入java文件 4.编译代理类,通过URLClassLoader把代理类加载到内存中 5.使用Const

设计模式课程 设计模式精讲 16-5 代理模式源码解析

1 源码解析 1.1 源码解析1(jdk中的应用) 1.2 源码解析2(spring中的应用) 1.3 源码解析3(mybaties中的应用) 1 源码解析 1.1 源码解析1(jdk中的应用) java.lang.reflect.Proxy public class Proxy implements java.io.Serializable { protected Proxy(InvocationHandler h) { doNewInstanceCheck(); this.h = h; }

JStorm与Storm源码分析(五)--SpoutOutputCollector与代理模式

本文主要是解析SpoutOutputCollector源码,顺便分析该类中所涉及的设计模式–代理模式. 首先介绍一下Spout输出收集器接口–ISpoutOutputCollector,该接口主要声明了以下3个抽象方法用来约束ISpoutOutputCollector的实现类.接口定义与方法说明如下: /** * ISpoutOutputCollector:Spout输出收集器接口 */ public interface ISpoutOutputCollector { /** * 改方法用来向外

JDK动态代理[2]----JDK动态代理的底层实现之Proxy源码分析

在上一篇里为大家简单介绍了什么是代理模式?为什么要使用代理模式?并用例子演示了一下静态代理和动态代理的实现,分析了静态代理和动态代理各自的优缺点.在这一篇中笔者打算深入源码为大家剖析JDK动态代理实现的机制,建议读者阅读本篇前可先阅读一下笔者上一篇关于代理模式的介绍<JDK动态代理[1]----代理模式实现方式的概要介绍> 上一篇动态代理的测试类中使用了Proxy类的静态方法newProxyInstance方法去生成一个代理类,这个静态方法接收三个参数,分别是目标类的类加载器,目标类实现的接口

(五)myBatis架构以及SQlSessionFactory,SqlSession,通过代理执行crud源码分析---待更

MyBatis架构 首先MyBatis大致上可以分为四层: 1.接口层:这个比较容易理解,就是指MyBatis暴露给我们的各种方法,配置,可以理解为你import进来的各种类.,告诉用户你可以干什么 2.数据处理层:顾名思义对数据的处理,当接收到一个sql语句时,比如 selecr *from person where id=#{id};  会进行这四步:参数处理---sql解析---sql执行----处理结果,这里我们重点关心sql的执行 3.框架支撑层:一些辅助操作,缓存机制,事务管理,连接

ABP源码分析三十五:ABP中动态WebAPI原理解析

动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能,这应该算是对DRY的最佳诠释了. 如下图所示,一行代码就为所有实现了IApplicationService的类型,自动创建对应的动态WebAPI. 这么Magic的功能是如何实现的呢? 本文为你揭开其Magic的外表.你会发现,实现如此Magic的功能,最关键的代码只有四行. 先思考一个问题:如果不

6.Sentinel源码分析—Sentinel是如何动态加载配置限流的?

Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. Sentinel源码分析-Sentinel是如何进行流量统计的? 3. Sentinel源码分析- QPS流量控制是如何实现的? 4.Sentinel源码分析- Sentinel是如何做到降级的? 5.Sentinel源码分析-Sentinel如何实现自适应限流? 有时候我们做限流的时候并不想直接写死在代码里面,然后每次要改规则,或者增加规则的时候只能去重启应用来解决.而是希望能

转:Mongodb源码分析之Replication模式

原文出处:http://www.cnblogs.com/daizhj/archive/2011/06/13/mongodb_sourcecode_rep mongodb中提供了复制(Replication)机制,通过该机制可以帮助我们很容易实现读写分离方案,并支持灾难恢复(服务器断电)等意外情况下的数据安全. 在老版本(1.6)中,Mongo提供了两种方式的复制:master-slave及replica pair模式(注:mongodb最新支持的replset复制集方式可看成是pair的升级版,