码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-07-26 17:22:25      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:

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的代码实现来查看动态代理对框架的作用。



?

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

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

标签:

原文地址:http://blog.csdn.net/mergades/article/details/47069371

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!