继上一篇博客设计模式之代理模式学习之后http://blog.csdn.net/u014427391/article/details/75115928,本博客介绍JDK动态代理的实现原理,学习一下JDK动态代理的源码。

Proxy类。该类即为动态代理类,可以使用反编译工具查看jdk里源码。JDK动态代理实现主要由Proxy类的newProxyInstance()方法实现。实现起来很容易,但是学习都要学习原理,所以本博客主要介绍jdk动态代理实现的源码。

newProxyInstance()方法用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示被代理类实现的接口列表,第三个参数h表示所指派的调用处理程序类。

首先写个例子实现jdk动态代理

主题接口类:

  1. public interface IHello {
  2. public void sayHello();
  3. }

被代理的类:

  1. public class Hello implements IHello{
  2. public void sayHello() {
  3. System.out.println("hello!");
  4. }
  5. }

JDK动态代理InvocationHandler类

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. public class MyInvocationHandler implements InvocationHandler {
  5. private Object target;//委托类
  6. public MyInvocationHandler(Object target){
  7. this.target=target;
  8. }
  9. @Override
  10. public Object invoke(Object o, Method method, Object[] args) throws Throwable {
  11. /**代理环绕**/
  12. //执行实际的方法
  13. Object invoke = method.invoke(target, args);
  14. return invoke;
  15. }
  16. }

写个类模拟字节码文件生成:

  1. import java.lang.reflect.Proxy;
  2. /**
  3. * Created by Nicky on 2017/7/20 0020.
  4. */
  5. public class Test {
  6. public static void main(String[] args){
  7. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  8. IHello ihello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), //加载接口的类加载器
  9. new Class[]{IHello.class}, //一组接口
  10. new MyInvocationHandler(new Hello())); //自定义的InvocationHandler
  11. ihello.sayHello();
  12. }
  13. }

实现jdk动态代理是很容易的,不过现在介绍一下jdk源码,理解一下原理实现

下面看一下Proxy类里的newProxyInstance方法

  1. @CallerSensitive
  2. public static Object newProxyInstance(ClassLoader loader,
  3. Class<?>[] interfaces,
  4. InvocationHandler h)
  5. throws IllegalArgumentException
  6. {
  7. Objects.requireNonNull(h);
  8. //对象的拷贝
  9. final Class<?>[] intfs = interfaces.clone();
  10. /*
  11. * 权限安全检查
  12. */
  13. final SecurityManager sm = System.getSecurityManager();
  14. if (sm != null) {
  15. checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
  16. }
  17. /*
  18. * Look up or generate the designated proxy class.
  19. * (查找或生产指定的代理类。)
  20. */
  21. Class<?> cl = getProxyClass0(loader, intfs);
  22. /*
  23. * Invoke its constructor with the designated invocation handler.
  24. * (使用指定的调用处理程序调用它的构造函数。)
  25. */
  26. try {
  27. if (sm != null) {
  28. checkNewProxyPermission(Reflection.getCallerClass(), cl);
  29. }
  30. //获取代理类的构造函数
  31. final Constructor<?> cons = cl.getConstructor(constructorParams);
  32. final InvocationHandler ih = h;
  33. /*
  34. * onstructor、Filed、Method都继承自java.lang.reflect.AccessibleObject,
  35. * 访问非public的方法或者字段都会产生IllegalAccessException异常
  36. */
  37. if (!Modifier.isPublic(cl.getModifiers())) {
  38. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  39. public Void run() {
  40. cons.setAccessible(true);//setAccessible()为true可以绕过默认的权限检查
  41. return null;
  42. }
  43. });
  44. }
  45. //根据代理类的构造函数来创建代理对象
  46. return cons.newInstance(new Object[]{h});
  47. } catch (IllegalAccessException|InstantiationException e) {
  48. throw new InternalError(e.toString(), e);
  49. } catch (InvocationTargetException e) {
  50. Throwable t = e.getCause();
  51. if (t instanceof RuntimeException) {
  52. throw (RuntimeException) t;
  53. } else {
  54. throw new InternalError(t.toString(), t);
  55. }
  56. } catch (NoSuchMethodException e) {
  57. throw new InternalError(e.toString(), e);
  58. }
  59. }

从newProxyInstance方法可以看出,生产代理类是由getProxyClass0获取或者生成的。下面看一下getProxyClass0方法,从方法可以看出如果缓存中有代理类就直接返回代理的副本,否就使用ProxyClassFactory创建代理类。

  1. /**
  2. * Generate a proxy class. Must call the checkProxyAccess method
  3. * to perform permission checks before calling this.
  4. */
  5. private static Class<?> getProxyClass0(ClassLoader loader,
  6. Class<?>... interfaces) {
  7. //接口列表数目不能超过65535,因为在class文件中,这些个数都是用4位16进制表示的,所以最大值是2的16次方-1
  8. if (interfaces.length > 65535) {
  9. throw new IllegalArgumentException("interface limit exceeded");
  10. }
  11. // If the proxy class defined by the given loader implementing
  12. // the given interfaces exists, this will simply return the cached copy;
  13. // otherwise, it will create the proxy class via the ProxyClassFactory
  14. //如果缓存中有代理类就直接返回代理的副本,否就使用ProxyClassFactory创建代理类
  15. return proxyClassCache.get(loader, interfaces);
  16. }

proxyClassCache是一个WeakCache类型的缓存,它的构造函数有两个参数,其中一个就是用于生成代理类的ProxyClassFactory,看一下proxyClassCache.get方法的代码:

  1. public V get(K key, P parameter) {
  2. Objects.requireNonNull(parameter);
  3. //清理持有弱引用的WeakHashMap这种数据结构
  4. expungeStaleEntries();
  5. //从队列中获取cacheKey
  6. Object cacheKey = CacheKey.valueOf(key, refQueue);
  7. // lazily install the 2nd level valuesMap for the particular cacheKey
  8. //懒加载的方式封装第二层valueMap,ConcurrentMap是一种线程安全的Map
  9. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  10. if (valuesMap == null) {
  11. ConcurrentMap<Object, Supplier<V>> oldValuesMap
  12. = map.putIfAbsent(cacheKey,
  13. valuesMap = new ConcurrentHashMap<>());
  14. if (oldValuesMap != null) {
  15. valuesMap = oldValuesMap;
  16. }
  17. }
  18. // create subKey and retrieve the possible Supplier<V> stored by that
  19. // subKey from valuesMap
  20. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  21. Supplier<V> supplier = valuesMap.get(subKey);
  22. Factory factory = null;
  23. while (true) {
  24. if (supplier != null) {
  25. // supplier might be a Factory or a CacheValue<V> instance
  26. //核心代码,从supplier或者value,可能返回工厂实例或者Cache实例,返回实现InvokeHandler的类并包含了所需要的信息。
  27. V value = supplier.get();
  28. if (value != null) {
  29. return value;
  30. }
  31. }
  32. // else no supplier in cache
  33. // or a supplier that returned null (could be a cleared CacheValue
  34. // or a Factory that wasn't successful in installing the CacheValue)
  35. // lazily construct a Factory
  36. //懒加载方式构建工厂实例
  37. if (factory == null) {
  38. factory = new Factory(key, parameter, subKey, valuesMap);
  39. }
  40. /**填充supplier**/
  41. if (supplier == null) {
  42. supplier = valuesMap.putIfAbsent(subKey, factory);
  43. if (supplier == null) {
  44. // successfully installed Factory
  45. supplier = factory;
  46. }
  47. // else retry with winning supplier
  48. } else {
  49. if (valuesMap.replace(subKey, supplier, factory)) {
  50. // successfully replaced
  51. // cleared CacheEntry / unsuccessful Factory
  52. // with our Factory
  53. supplier = factory;
  54. } else {
  55. // retry with current supplier
  56. supplier = valuesMap.get(subKey);
  57. }
  58. }
  59. }
  60. }

若缓存中找不到代理类,就使用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(统一所以代理类的前缀名都以$Proxy开始)
  9. private static final String proxyClassNamePrefix = "$Proxy";
  10. // next number to use for generation of unique proxy class names
  11. //给每个代理类名加个唯一的编号,如$Proxy0,$Proxy1等等
  12. private static final AtomicLong nextUniqueNumber = new AtomicLong();
  13. @Override
  14. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  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. //通过类名加载每一个接口运行时的信息
  23. try {
  24. interfaceClass = Class.forName(intf.getName(), false, loader);
  25. } catch (ClassNotFoundException e) {
  26. }
  27. //验证使用classLoad加载的类与传入的类是否相同
  28. if (interfaceClass != intf) {
  29. throw new IllegalArgumentException(
  30. intf + " is not visible from class loader");
  31. }
  32. /*
  33. * Verify that the Class object actually represents an
  34. * interface.
  35. * 验证传入的是否为接口类型,因为jdk动态代理只支持接口类型
  36. */
  37. if (!interfaceClass.isInterface()) {
  38. throw new IllegalArgumentException(
  39. interfaceClass.getName() + " is not an interface");
  40. }
  41. /*
  42. * Verify that this interface is not a duplicate.
  43. * 验证接口是否重复
  44. */
  45. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  46. throw new IllegalArgumentException(
  47. "repeated interface: " + interfaceClass.getName());
  48. }
  49. }
  50. String proxyPkg = null; // package to define proxy class in
  51. int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
  52. /*
  53. * Record the package of a non-public proxy interface so that the
  54. * proxy class will be defined in the same package. Verify that
  55. * all non-public proxy interfaces are in the same package.
  56. * 验证传入的接口中有没有非public的接口,若有,就将这些接口全部放在一个包里定义
  57. */
  58. for (Class<?> intf : interfaces) {
  59. int flags = intf.getModifiers();
  60. if (!Modifier.isPublic(flags)) {
  61. accessFlags = Modifier.FINAL;
  62. String name = intf.getName();
  63. int n = name.lastIndexOf('.');
  64. //substring包名
  65. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  66. if (proxyPkg == null) {
  67. proxyPkg = pkg;
  68. } else if (!pkg.equals(proxyPkg)) {
  69. throw new IllegalArgumentException(
  70. "non-public interfaces from different packages");
  71. }
  72. }
  73. }
  74. if (proxyPkg == null) {
  75. // if no non-public proxy interfaces, use com.sun.proxy package
  76. //(如果没有非公共的代理接口,请使用com.sun.proxy包)
  77. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  78. }
  79. /*
  80. * Choose a name for the proxy class to generate.(为代理类选择一个名称来生成)
  81. */
  82. long num = nextUniqueNumber.getAndIncrement();
  83. //生产随机代理类的类名,$Proxy+num
  84. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  85. /*
  86. * Generate the specified proxy class.
  87. * 生产代理类的字节码文件,实现过程看generateProxyClass()方法
  88. */
  89. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  90. proxyName, interfaces, accessFlags);
  91. try {
  92. return defineClass0(loader, proxyName,
  93. proxyClassFile, 0, proxyClassFile.length);
  94. } catch (ClassFormatError e) {
  95. /*
  96. * A ClassFormatError here means that (barring bugs in the
  97. * proxy class generation code) there was some other
  98. * invalid aspect of the arguments supplied to the proxy
  99. * class creation (such as virtual machine limitations
  100. * exceeded).
  101. */
  102. throw new IllegalArgumentException(e.toString());
  103. }
  104. }
  105. }

从ProxyClassFactory类可以看出生产字节码文件的执行代码由generateProxyClass方法执行:

  1. public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
  2. //新建ProxyGenerator实例,放入参数proxyName, interfaces, accessFlags,也即代理名称,接口列表,是否允许代理的flag标志
  3. ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
  4. //真正实现生产字节码文件的方法
  5. final byte[] var4 = var3.generateClassFile();
  6. //检查是否允许生产文件,如果可以就保存class文件到本地
  7. if(saveGeneratedFiles) {
  8. AccessController.doPrivileged(new PrivilegedAction() {
  9. public Void run() {
  10. try {
  11. int var1 = var0.lastIndexOf(46);
  12. Path var2;
  13. if(var1 > 0) {
  14. Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
  15. Files.createDirectories(var3, new FileAttribute[0]);
  16. var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
  17. } else {
  18. var2 = Paths.get(var0 + ".class", new String[0]);
  19. }
  20. Files.write(var2, var4, new OpenOption[0]);
  21. return null;
  22. } catch (IOException var4x) {
  23. throw new InternalError("I/O exception saving generated file: " + var4x);
  24. }
  25. }
  26. });
  27. }
  28. return var4;
  29. }

看了这么久,终于知道generateClassFile是真正执行class文件生成的方法,现在看一下generateClassFile的代码:

  1. private byte[] generateClassFile() {
  2. /**将Object类的三个方法hashCode、equals、toString都加到代理方法里,生产class文件时一起重写**/
  3. this.addProxyMethod(hashCodeMethod, Object.class);
  4. this.addProxyMethod(equalsMethod, Object.class);
  5. this.addProxyMethod(toStringMethod, Object.class);
  6. Class[] var1 = this.interfaces;
  7. int var2 = var1.length;
  8. int var3;
  9. Class var4;
  10. //将接口和接口下的方法对应起来
  11. for(var3 = 0; var3 < var2; ++var3) {
  12. var4 = var1[var3];
  13. Method[] var5 = var4.getMethods();
  14. int var6 = var5.length;
  15. for(int var7 = 0; var7 < var6; ++var7) {
  16. Method var8 = var5[var7];
  17. this.addProxyMethod(var8, var4);
  18. }
  19. }
  20. Iterator var11 = this.proxyMethods.values().iterator();
  21. List var12;
  22. //检查所有代理方法的返回类型
  23. while(var11.hasNext()) {
  24. var12 = (List)var11.next();
  25. checkReturnTypes(var12);
  26. }
  27. Iterator var15;
  28. try {
  29. //将构造函数放在方法里,这个构造方法只有一个,即一个带有InvocationHandler实例的构造方法
  30. this.methods.add(this.generateConstructor());
  31. var11 = this.proxyMethods.values().iterator();
  32. //遍历代理方法
  33. while(var11.hasNext()) {
  34. var12 = (List)var11.next();
  35. var15 = var12.iterator();
  36. while(var15.hasNext()) {
  37. ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
  38. //给每一个代理方法加一个Method类型的属性,数字10是class文件的标识符,代表这些属性都是private static的
  39. this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
  40. //将方法都加到代理类的方法里
  41. this.methods.add(var16.generateMethod());
  42. }
  43. }
  44. //加入一个静态的类构造方法,将每一个属性初始化
  45. this.methods.add(this.generateStaticInitializer());
  46. } catch (IOException var10) {
  47. throw new InternalError("unexpected I/O Exception", var10);
  48. }
  49. //方法和属性个数都不能超过65535,因为在class文件中,这些个数都是用4位16进制表示的,所以最大值是2的16次方-1
  50. if(this.methods.size() > '\uffff') {
  51. throw new IllegalArgumentException("method limit exceeded");
  52. } else if(this.fields.size() > '\uffff') {
  53. throw new IllegalArgumentException("field limit exceeded");
  54. } else {
  55. //将类名中的.转成成斜线为了写入class文件。
  56. this.cp.getClass(dotToSlash(this.className));
  57. this.cp.getClass("java/lang/reflect/Proxy");
  58. var1 = this.interfaces;
  59. var2 = var1.length;
  60. for(var3 = 0; var3 < var2; ++var3) {
  61. var4 = var1[var3];
  62. this.cp.getClass(dotToSlash(var4.getName()));
  63. }
  64. this.cp.setReadOnly();
  65. //开始真正的写class文件
  66. ByteArrayOutputStream var13 = new ByteArrayOutputStream();
  67. DataOutputStream var14 = new DataOutputStream(var13);
  68. try {
  69. //写入class文件的标识号,标识这是一个class文件
  70. var14.writeInt(-889275714);
  71. //次版本号0
  72. var14.writeShort(0);
  73. //主版本号,49代表的是JDK1.5
  74. var14.writeShort(49);
  75. this.cp.write(var14);
  76. var14.writeShort(this.accessFlags);
  77. //写入代理类的类名
  78. var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
  79. var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
  80. //写入代理类所实现的接口数量
  81. var14.writeShort(this.interfaces.length);
  82. Class[] var17 = this.interfaces;
  83. int var18 = var17.length;
  84. for(int var19 = 0; var19 < var18; ++var19) {
  85. Class var22 = var17[var19];
  86. var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
  87. }
  88. //写入属性个数
  89. var14.writeShort(this.fields.size());
  90. var15 = this.fields.iterator();
  91. //写入属性描述
  92. while(var15.hasNext()) {
  93. ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
  94. var20.write(var14);
  95. }
  96. //写入方法个数
  97. var14.writeShort(this.methods.size());
  98. var15 = this.methods.iterator();
  99. //写入方法描述,方法的code属性,以及构造方法和类构造方法
  100. while(var15.hasNext()) {
  101. ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
  102. var21.write(var14);
  103. }
  104. var14.writeShort(0);
  105. return var13.toByteArray();
  106. } catch (IOException var9) {
  107. throw new InternalError("unexpected I/O Exception", var9);
  108. }
  109. }
  110. }

使用反编译工具查看生产的字节码文件代码,说明了下文件中生成的部分与刚才分析的时候写入的过程的对应关系。:

  1. package com.sun.proxy;
  2. import IHello;
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.lang.reflect.UndeclaredThrowableException;
  7. //生产的代理类都是以$Proxy+唯一的数字为类名的,继承Proxy类同时implements你主题接口
  8. public final class $Proxy0 extends Proxy
  9. implements IHello
  10. {
  11. private static Method m1;
  12. private static Method m3;
  13. private static Method m2;
  14. private static Method m0;
  15. //将InvocationHandler实例放在构造方法里
  16. public $Proxy0(InvocationHandler paramInvocationHandler)
  17. throws
  18. {
  19. super(paramInvocationHandler);
  20. }
  21. //重写Object的equals方法
  22. public final boolean equals(Object paramObject)
  23. throws
  24. {
  25. try
  26. {
  27. return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  28. }
  29. catch (RuntimeException localRuntimeException)
  30. {
  31. throw localRuntimeException;
  32. }
  33. catch (Throwable localThrowable)
  34. {
  35. }
  36. throw new UndeclaredThrowableException(localThrowable);
  37. }
  38. public final void sayHello()
  39. throws
  40. {
  41. try
  42. {
  43. this.h.invoke(this, m3, null);
  44. return;
  45. }
  46. catch (RuntimeException localRuntimeException)
  47. {
  48. throw localRuntimeException;
  49. }
  50. catch (Throwable localThrowable)
  51. {
  52. }
  53. throw new UndeclaredThrowableException(localThrowable);
  54. }
  55. public final String toString()
  56. throws
  57. {
  58. try
  59. {
  60. return (String)this.h.invoke(this, m2, null);
  61. }
  62. catch (RuntimeException localRuntimeException)
  63. {
  64. throw localRuntimeException;
  65. }
  66. catch (Throwable localThrowable)
  67. {
  68. }
  69. throw new UndeclaredThrowableException(localThrowable);
  70. }
  71. public final int hashCode()
  72. throws
  73. {
  74. try
  75. {
  76. return ((Integer)this.h.invoke(this, m0, null)).intValue();
  77. }
  78. catch (RuntimeException localRuntimeException)
  79. {
  80. throw localRuntimeException;
  81. }
  82. catch (Throwable localThrowable)
  83. {
  84. }
  85. throw new UndeclaredThrowableException(localThrowable);
  86. }
  87. static
  88. {
  89. try
  90. {
  91. //每一个属性所代表的Method都是与上面加入代理方法列表时与固定类绑定的,这是class文件中的格式,方法要与固定的类绑定
  92. m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
  93. m3 = Class.forName("IHello").getMethod("sayHello", new Class[0]);
  94. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  95. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  96. return;
  97. }
  98. catch (NoSuchMethodException localNoSuchMethodException)
  99. {
  100. throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
  101. }
  102. catch (ClassNotFoundException localClassNotFoundException)
  103. {
  104. }
  105. throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  106. }
  107. }

JDK动态代理源码学习的更多相关文章

  1. 动态代理学习(二)JDK动态代理源码分析

    上篇文章我们学习了如何自己实现一个动态代理,这篇文章我们从源码角度来分析下JDK的动态代理 先看一个Demo: public class MyInvocationHandler implements ...

  2. 深入剖析JDK动态代理源码实现

    动态代理.静态代理优缺点优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性.这是代理的共有优点.动态代理只有在用到被代理对象的时候才会对被代理类进行类加载. 而静态代理在编译器就已经开始占内存了 ...

  3. 设计模式之JDK动态代理源码分析

    这里查看JDK1.8.0_65的源码,通过debug学习JDK动态代理的实现原理 大概流程 1.为接口创建代理类的字节码文件 2.使用ClassLoader将字节码文件加载到JVM 3.创建代理类实例 ...

  4. jdk 动态代理源码分析

    闲来无事,撸撸源码 使用方法 直接看代码吧.. package com.test.demo.proxy; import java.lang.reflect.InvocationHandler; imp ...

  5. JDK动态代理源码解析

    动态代理.静态代理优缺点     关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的 ...

  6. JDK动态代理源码分析

    先抛出一个问题,JDK的动态代理为什么不支持对实现类的代理,只支持接口的代理??? 首先来看一下如何使用JDK动态代理.JDK提供了Java.lang.reflect.Proxy类来实现动态代理的,可 ...

  7. JDK动态代理源码剖析

    关键代码: 1.Proxy.newInstance: private static final Class<?>[] constructorParams = { InvocationHan ...

  8. java 1.8 动态代理源码分析

    JDK8动态代理源码分析 动态代理的基本使用就不详细介绍了: 例子: class proxyed implements pro{ @Override public void text() { Syst ...

  9. java动态代理源码解析

    众所周知,java动态代理同反射原理一直是许多框架的底层实现,之前一直没有时间来分析动态代理的底层源码,现结合源码分析一下动态代理的底层实现 类和接口 java动态代理的主要类和接口有:java.la ...

随机推荐

  1. 利用 os.walk() 遍历目录

    os.walk: walk(top, topdown=True, onerror=None, followlinks=False) 参数: top 要遍历的目录地址 topdown 为真,则优先遍历t ...

  2. 一天搞定CSS: 标签样式初始化(CSS reset)及淘宝样式初始化代码--09

    样式初始化:是指对HTML中某些标签的默认样式进行清除 样式初始化目的: 不同浏览器的默认样式不一样,若不清理,会导致相同的代码在浏览器中解析结果不一样,为了避免这种情况,所以需要进行样式初始化. 代 ...

  3. Python之正则表达式(re模块)

    本节内容 re模块介绍 使用re模块的步骤 re模块简单应用示例 关于匹配对象的说明 说说正则表达式字符串前的r前缀 re模块综合应用实例 正则表达式(Regluar Expressions)又称规则 ...

  4. JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)

    抽象的概念 狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象. 这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这 ...

  5. 2015阿里巴巴安全峰会PPT

    有幸参加了阿里巴巴安全峰会,不得不佩服阿里巴巴神盾局,真牛B!然后亲眼目睹了第二天的各大厂商牛(zhuang)B人才上台演讲,有被捧的,有被喷的,呵呵.总的来说,大家的分享精神还是阔以的. 下面是会议 ...

  6. (转)Javascript的DOM操作 - 性能优化

    转载:https://my.oschina.net/blogshi/blog/198910 摘要: 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维 ...

  7. Nginx+Keepalived 主备高可用 安装与配置

    环境说明:操作系统:CentOS6.7 x86_64Nginx版本:nginx-1.9.7Keepalived版本:keepalived-1.2.24 主nginx + Keepalived :10. ...

  8. SQLServer类型与Java类型转换问题解决

    ResultSet 接口提供用于从当前行获取列值的获取 方法(getBoolean.getLong 等).可以使用列的索引编号或列的名称获取值.一般情况下,使用列索引较为高效.列从 1 开始编号.为了 ...

  9. ecshop循环计数

    循环依次递增+1 <!-- {foreach from=$comments item=comment name=comment} --> {$smarty.foreach.comment. ...

  10. 【面经】腾讯和YY实习生面试总结

    [前言] 之前的四月份和五月份各面试了腾讯和YY的暑假实习,腾讯的失败了,YY的成功了.面试中我总会遇到自己不懂的,所幸的是不懂的越来越少,自己也一步一脚印得攻克自己不懂的.此时六月份的我再回顾起来, ...