分析版本jdk1.8

在分析jdk动态代理之前,先来了解java WeakReference弱引用的使用。运行期创建目标对象的代理非常耗时,使用缓存来存储生成的代理类显得尤为重要。jdk动态代理使用弱引用指向cache中的代理类,以便代理类对象能够被GC回收。

在java中,当一个对象O被创建时,它被放在Heap里,当GC运行的时候,如果发现没有任何引用指向O,O就会被回收以腾出内存空间,或者说,一个对象被回收,必须满足两个条件:1)没有任何引用指向它;2)GC被运行。在现实情况写代码的时候, 我们往往通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收 (可以用java -verbose:gc来观察gc的行为)。

[java] view plaincopy
  1. Object c = new Car();
  2. c=null;

但是, 手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的.  对于简单的情况, 手动置空是不需要程序员来做的, 因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了.
但是, 也有特殊例外. 当使用cache的时候, 由于cache的对象正是程序运行需要的, 那么只要程序正在运行, cache中的引用就不会被GC给(或者说, cache中的reference拥有了和主程序一样的life cycle). 那么随着cache中的reference越来越多, GC无法回收的object也越来越多, 无法被自动回收. 当这些object需要被回收时, 回收这些object的任务只有交给程序编写者了. 然而这却违背了GC的本质(自动回收可以回收的objects).所以, java中引入了weak reference. 相对于前面举例中的strong reference:

[java] view plaincopy
  1. Object c = new Car(); //只要c还指向car object, car object就不会被回收

当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收. weak reference的语法是:

[java] view plaincopy
  1. WeakReference<Car> weakCar = new WeakReference(Car)(car);

当要获得weak reference引用的object时, 首先需要判断它是否已经被回收:

[java] view plaincopy
  1. weakCar.get();

如果此方法为空, 那么说明weakCar指向的对象已经被回收了,下面来看一个例子:

[java] view plaincopy
  1. package weakreference;
  2. /**
  3. * @author ywchen
  4. */
  5. public class Car {
  6. private double price;
  7. private String colour;
  8. public Car(double price, String colour){
  9. this.price = price;
  10. this.colour = colour;
  11. }
  12. public double getPrice() {
  13. return price;
  14. }
  15. public void setPrice(double price) {
  16. this.price = price;
  17. }
  18. public String getColour() {
  19. return colour;
  20. }
  21. public void setColour(String colour) {
  22. this.colour = colour;
  23. }
  24. public String toString(){
  25. return colour +"car costs $"+price;
  26. }
  27. }
  28. package weakreference;
  29. import java.lang.ref.WeakReference;
  30. /**
  31. * @author ywchen
  32. */
  33. public class TestWeakReference {
  34. public static void main(String[] args) {
  35. Car car = new Car(22000,"silver");
  36. WeakReference<Car> weakCar = new WeakReference<Car>(car);
  37. int i=0;
  38. while(true){
  39. if(weakCar.get()!=null){
  40. i++;
  41. System.out.println("Object is alive for "+i+" loops - "+weakCar);
  42. }else{
  43. System.out.println("Object has been collected.");
  44. break;
  45. }
  46. }
  47. }
  48. }

在上例中, 程序运行一段时间后, 程序打印出"Object has been collected." 说明, weak reference指向的对象的被回收了.

ReferenceQueue
在weak reference指向的对象被回收后, weak reference本身其实也就没有用了. java提供了一个ReferenceQueue来保存这些所指向的对象已经被回收的reference. 用法是在定义WeakReference的时候将一个ReferenceQueue的对象作为参数传入构造函数.

jdk动态代理

面向对象编程(OOP)有一些弊端,为多个不具有继承关系的对象引入同一个公共行为,例如日志、安全监测等,需要在每个对象里引入公共行为,导致程序中产生大量重复代码。不便于维护。所以就有了一个面向对象编程的补充,即面向切面编程(AOP),AOP所关注的是横向,OOP关注的是纵向。AOP的实现,可采用JDK动态代理、CGLIB代理。

JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现来完成目标对象的代理。

CBLIB代理:实现原理类似于JDK动态代理,它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层依靠ASM(开源的字节码编辑类库)操作字节码实现,性能比JDK强。

jdk动态代理实现示例

1. 新建委托类

[java] view plaincopy
  1. /**
  2. * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
  3. * @author yawenchen
  4. * @since 2016-11-15
  5. *
  6. */
  7. public interface UserService {
  8. /**
  9. * 目标方法
  10. */
  11. public abstract void add();
  12. }
[java] view plaincopy
  1. /**
  2. * 目标对象
  3. * @author yawenchen
  4. * @since 2016-11-15
  5. *
  6. */
  7. public class UserServiceImpl implements UserService {
  8. /* (non-Javadoc)
  9. * @see dynamic.proxy.UserService#add()
  10. */
  11. public void add() {
  12. System.out.println("--------------------add---------------");
  13. }
  14. }

UserService 是一个接口,UserServiceImpl 接口的实现类,也称委托类。动态代理要求代理对象必须是接口的实现类。因此UserServiceImpl 实现了UserService 。

2. 实现InvocationHandlerj接口

[java] view plaincopy
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. /**
  5. * 实现自己的InvocationHandler
  6. * @author ywchen
  7. * @since 2016-11-15
  8. *
  9. */
  10. public class MyInvocationHandler implements InvocationHandler {
  11. // 目标对象
  12. private Object target;
  13. /**
  14. * 构造方法
  15. * @param target 目标对象
  16. */
  17. public MyInvocationHandler(Object target) {
  18. super();
  19. this.target = target;
  20. }
  21. /**
  22. * 执行目标对象的方法
  23. */
  24. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  25. // 在目标对象的方法执行之前简单的打印一下
  26. System.out.println("------------------before------------------");
  27. // 执行目标对象的方法
  28. Object result = method.invoke(target, args);
  29. // 在目标对象的方法执行之后简单的打印一下
  30. System.out.println("-------------------after------------------");
  31. return result;
  32. }
  33. /**
  34. * 获取目标对象的代理对象
  35. * @return 代理对象
  36. */
  37. public Object getProxy() {
  38. return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
  39. target.getClass().getInterfaces(), this);
  40. }
  41. }

target属性,表示代理的目标对象。InvocationHandler是负责连接代理对象与目标对象的自定义中间类MyInvocationHandler必须实现的接口,只有一个方法。
public Object invoke(Object proxy, Method method, Object[] args)
参数说明:Proxy表示通过Proxy.newProxyInstance()生成的代理类对象。Method表示目标对象被调用的方法。Args表示目标对象被调用方法的输入参数。

3. 通过Proxy类静态函数生成代理对象

[java] view plaincopy
  1. public class ProxyTest {
  2. public static void main(String[] args) {
  3. //实例化目标对象
  4. UserService userService  = new UserSericeImpl();
  5. //实例化InvocationHander
  6. MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
  7. //根据目标对象生成代理对象
  8. UserService proxy = (UserService)invocationHandler.getProxy();
  9. //调用代理对象的方法
  10. proxy.add();
  11. }
  12. }

执行结果
------------------before------------------ 
--------------------add--------------- 
-------------------after------------------

动态代理原理

[java] view plaincopy
  1. /**
  2. * loader :类加载器
  3. * interfaces:目标对象实现的接口
  4. * h:InvocationHandler的实现类
  5. */
  6. public static Object newProxyInstance(ClassLoader loader,
  7. Class<?>[] interfaces,
  8. InvocationHandler h)
  9. throws IllegalArgumentException
  10. {
  11. Objects.requireNonNull(h);
  12. final Class<?>[] intfs = interfaces.clone();
  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. Class<?> cl = getProxyClass0(loader, intfs);
  21. /*
  22. * Invoke its constructor with the designated invocation handler.
  23. */
  24. try {
  25. if (sm != null) {
  26. checkNewProxyPermission(Reflection.getCallerClass(), cl);
  27. }
  28. //调用代理对象的构造函数(代理对象的构造函数$Proxy0(InvocationHandler h),通过字节码反编译可以查看生成的代理类)
  29. final Constructor<?> cons = cl.getConstructor(constructorParams);
  30. final InvocationHandler ih = h;
  31. if (!Modifier.isPublic(cl.getModifiers())) {
  32. AccessController.doPrivileged(new PrivilegedAction<Void>() {
  33. public Void run() {
  34. cons.setAccessible(true);
  35. return null;
  36. }
  37. });
  38. }
  39. //生成代理类的实例,并把MyInvocationHander的实例作为构造函数参数传入
  40. return cons.newInstance(new Object[]{h});
  41. } catch (IllegalAccessException|InstantiationException e) {
  42. throw new InternalError(e.toString(), e);
  43. } catch (InvocationTargetException e) {
  44. Throwable t = e.getCause();
  45. if (t instanceof RuntimeException) {
  46. throw (RuntimeException) t;
  47. } else {
  48. throw new InternalError(t.toString(), t);
  49. }
  50. } catch (NoSuchMethodException e) {
  51. throw new InternalError(e.toString(), e);
  52. }
  53. }

进到getProxyClass0方法

[java] view plaincopy
  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. }

proxyClassCache为WeakCache的实例化对象,在Proxy类中定义,表示代理类的缓存。定义如下:

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

KeyFactory、ProxyClassFactory是WeakCache的内部静态类。实现了BiFunction接口。WeakCache实例化时作为构造函数参数传入,继承关系如下:

主要的代码如下:

[java] view plaincopy
  1. public interface BiFunction<T, U, R> {
  2. R apply(T t, U u);
  3. }
[java] view plaincopy
  1. private static final class ProxyClassFactory
  2. implements BiFunction<ClassLoader, Class<?>[], Class<?>>
  3. {
  4. // prefix for all proxy class names 代理类的前缀
  5. private static final String proxyClassNamePrefix = "$Proxy";
  6. // next number to use for generation of unique proxy class names
  7. //生成唯一的代理类名称
  8. private static final AtomicLong nextUniqueNumber = new AtomicLong();
  9. @Override
  10. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  11. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  12. for (Class<?> intf : interfaces) {
  13. /*
  14. * Verify that the class loader resolves the name of this
  15. * interface to the same Class object.
  16. */
  17. //确保接口的类对象与类加载器加载的类对象相同,且由同一个加载器加载。《深入理解java虚拟机》提到,类加载器虽然只用于实现类的加载动作,但在java程序起的作用远不止于类的加载。对于任何一个类,都需要由加载它的的类加载器和这个类本身一同确立其在java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间,通俗点,比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。interfaceClass = Class.forName(intf.getName(), false, loader);验证类是否相等,实现原理如上所述。
  18. Class<?> interfaceClass = null;
  19. try {
  20. interfaceClass = Class.forName(intf.getName(), false, loader);
  21. } catch (ClassNotFoundException e) {
  22. }
  23. if (interfaceClass != intf) {
  24. throw new IllegalArgumentException(
  25. intf + " is not visible from class loader");
  26. }
  27. /*
  28. * Verify that the Class object actually represents an
  29. * interface. 验证类对象表示的是接口
  30. */
  31. if (!interfaceClass.isInterface()) {
  32. throw new IllegalArgumentException(
  33. interfaceClass.getName() + " is not an interface");
  34. }
  35. /*
  36. * Verify that this interface is not a duplicate. 验证接口未重复
  37. */
  38. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  39. throw new IllegalArgumentException(
  40. "repeated interface: " + interfaceClass.getName());
  41. }
  42. }
  43. String proxyPkg = null;     // package to define proxy class in定义待生成的代理类所在包名
  44. int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
  45. /*
  46. * Record the package of a non-public proxy interface so that the
  47. * proxy class will be defined in the same package.  Verify that
  48. * all non-public proxy interfaces are in the same package.非public修饰的代理接口,需要定义在相同的包中,如果非public修饰的接口不在相同包,会因访问权限的限制而无法访问。intf.getModifiers()返回的是一个整数,用不同的位开关表示接口中public/final修饰符的使用情况。
  49. */
  50. for (Class<?> intf : interfaces) {
  51. int flags = intf.getModifiers();
  52. if (!Modifier.isPublic(flags)) {
  53. accessFlags = Modifier.FINAL;
  54. String name = intf.getName();
  55. int n = name.lastIndexOf('.');
  56. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  57. if (proxyPkg == null) {
  58. proxyPkg = pkg;   //代理对象的包名,如com.aop
  59. } else if (!pkg.equals(proxyPkg)) {
  60. throw new IllegalArgumentException(
  61. "non-public interfaces from different packages");
  62. }
  63. }
  64. }
  65. if (proxyPkg == null) {
  66. // if no non-public proxy interfaces, use com.sun.proxy package
  67. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  68. }
  69. /*
  70. * Choose a name for the proxy class to generate.
  71. */
  72. long num = nextUniqueNumber.getAndIncrement();
  73. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  74. /*
  75. * Generate the specified proxy class.
  76. *生成目标对象的代理类的字节码,并保存到硬盘中。
  77. */
  78. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
  79. proxyName, interfaces, accessFlags);
  80. try {
  81. //返回代理类对象,将字节码加载到内存中
  82. return defineClass0(loader, proxyName,
  83. proxyClassFile, 0, proxyClassFile.length);
  84. } catch (ClassFormatError e) {
  85. /*
  86. * A ClassFormatError here means that (barring bugs in the
  87. * proxy class generation code) there was some other
  88. * invalid aspect of the arguments supplied to the proxy
  89. * class creation (such as virtual machine limitations
  90. * exceeded).
  91. */
  92. throw new IllegalArgumentException(e.toString());
  93. }
  94. }
  95. }
[java] view plaincopy
  1. /**
  2. *映射接口数组到最后键的函数
  3. * 接口数组映射到最优键对象上(如实例化Key1时,接口作为Key1的构造函数参数,保存到Key1中), 同时,Key1/Key2/KeyX继承了WeakReference弱引用类类,因此接口所在的类对象被弱引用
  4. */
  5. private static final class KeyFactory
  6. implements BiFunction<ClassLoader, Class<?>[], Object>
  7. {
  8. @Override
  9. public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
  10. switch (interfaces.length) {
  11. case 1: return new Key1(interfaces[0]); // the most frequent
  12. case 2: return new Key2(interfaces[0], interfaces[1]);
  13. case 0: return key0;
  14. default: return new KeyX(interfaces);
  15. }
  16. }
  17. }

WeakCache类中定义的map变量如下:

[java] view plaincopy
  1. private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();

双层map映射,第一层key为ClassLoader,第二层key为接口的弱引用对象,value为代理类的Class对象。怎么看出是弱引用的呢,value中存放的值是一个类,该类继承了弱引用类WeakReference,我们的代理类在对象实例化时,通过构造函数传入。为对象添加引用,可看WeakReference用法。

第一层是类加载器,第二层才是类对象,为什么不用一层,代理类对象作为键呢,这里就涉及到类加载器的使用。记住一点,类的唯一性是由类加载器和类本身共同决定的。

对Supplier接口,Factory类进行说明,接下来的代码中会用到。

调用proxyClassCache.get(loader, interfaces),进入WeakCache的get方法。代码如下:

[java] view plaincopy
  1. public V get(K key, P parameter) {
  2. Objects.requireNonNull(parameter);
  3. expungeStaleEntries();
  4. //refQueue的类型为ReferenceQueue,存放对象的弱引用,CacheKey继承了WeakReference,因此key(ClassLoader)所在对象被弱引用,对象的应用存放在队列refQueue中。
  5. Object cacheKey = CacheKey.valueOf(key, refQueue);
  6. // lazily install the 2nd level valuesMap for the particular cacheKey
  7. //生成第一层key,从缓存中获取valuesMap,如果为空,则新建ConcurrentHashMap实例,把当前加载器和ConcurrentHashMap实例放到缓存中。
  8. ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  9. if (valuesMap == null) {
  10. ConcurrentMap<Object, Supplier<V>> oldValuesMap
  11. = map.putIfAbsent(cacheKey,
  12. valuesMap = new ConcurrentHashMap<>());
  13. if (oldValuesMap != null) {
  14. valuesMap = oldValuesMap;
  15. }
  16. }
  17. // create subKey and retrieve the possible Supplier<V> stored by that
  18. // subKey from valuesMap
  19. //subKeyFactory是Proxy类的内部静态类KeyFactory的实例对象
  20. //valueFactory是Proxy类的内容静态类ProxyClassFactory的实例对象
  21. //subKeyFactory.apply(key, parameter)返回接口的弱引用对象。subKey,即接口的弱引用对象作为第二层映射的键
  22. Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  23. Supplier<V> supplier = valuesMap.get(subKey);
  24. Factory factory = null;
  25. while (true) {
  26. if (supplier != null) {
  27. // supplier might be a Factory or a CacheValue<V> instance,supplier不为空,缓存中存在代理类
  28. V value = supplier.get();
  29. if (value != null) {  //value不为空,即代理类存在,将代理类返回。
  30. return value;
  31. }
  32. }
  33. // else no supplier in cache
  34. // or a supplier that returned null (could be a cleared CacheValue
  35. // or a Factory that wasn't successful in installing the CacheValue)
  36. // lazily construct a Factory
  37. if (factory == null) {
  38. factory = new Factory(key, parameter, subKey, valuesMap);
  39. }
  40. if (supplier == null) {
  41. supplier = valuesMap.putIfAbsent(subKey, factory);
  42. if (supplier == null) {
  43. // successfully installed Factory
  44. supplier = factory;
  45. }
  46. // else retry with winning supplier
  47. } else {
  48. if (valuesMap.replace(subKey, supplier, factory)) {
  49. // successfully replaced
  50. // cleared CacheEntry / unsuccessful Factory
  51. // with our Factory
  52. supplier = factory;
  53. } else {
  54. // retry with current supplier
  55. supplier = valuesMap.get(subKey);
  56. }
  57. }
  58. }
  59. }

上面执行流程中,主要的两个步骤为:

Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); subKey为接口对象的弱引用。 进入Proxy类的内部静态类KeyFactory,查看apply方法(本文前面提到的KeyFactory类)。

V value = supplier.get(); value为缓存中的代理类对象,Supplier是个接口,实现代码是在接口的实现类Factory中, 进入WeakCache类的内部类Factory,查看get方法。如下:

Supplier是接口

[java] view plaincopy
  1. public interface Supplier<T> {
  2. /**
  3. * Gets a result.
  4. *
  5. * @return a result
  6. */
  7. T get();
  8. }
  9. }

Factory是WeakCache的内部类, Factory实现了接口Supplier

[java] view plaincopy
  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. //valueFactory.apply(key, parameter) 返回代理类对象,即Class对象。
  30. //如果value不为空,说明缓存中已经存在代理类,可以直接返回。
  31. //通过前面的判断,已经能确定缓存中存在代理类,否则,程序是走不到这里来的。
  32. value = Objects.requireNonNull(valueFactory.apply(key, parameter));
  33. } finally {
  34. if (value == null) { // remove us on failure
  35. valuesMap.remove(subKey, this);
  36. }
  37. }
  38. // the only path to reach here is with non-null value
  39. assert value != null;
  40. // wrap value with CacheValue (WeakReference)
  41. CacheValue<V> cacheValue = new CacheValue<>(value);
  42. // try replacing us with CacheValue (this should always succeed)
  43. if (valuesMap.replace(subKey, this, cacheValue)) {
  44. // put also in reverseMap
  45. reverseMap.put(cacheValue, Boolean.TRUE);
  46. } else {
  47. throw new AssertionError("Should not reach here");
  48. }
  49. // successfully replaced us with new CacheValue -> return the value
  50. // wrapped by it
  51. return value;
  52. }
  53. }
在Facotry类的get方法中,value是由valueFactory.apply(key, parameter)生成,返回代理类Class对象。具体的实现可在本文前面提到的ValueFactory中查看。

JDK动态代理实现原理

Java WeakReference的理解与使用

JDK动态代理源码解析相关推荐

  1. jdk动态代理源码分析(一)---代理的定义

    最近在看rpc的实现原理,发现大部分通用的rpc框架在实现远程调用的时候,都是通过java动态代理封装好了通信细节,让用户可以像调用本地服务一样调用远程服务.但是关于java动态代理有两个问题想不通: ...

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

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

  3. 动态代理及JDK动态代理源码分析

    1.为什么要动态代理 现在有这样一个需求:在聊天系统中,把每一个所说的话记录到日志文件里面,初学者可能是这样来设计 在speak方法中调用log方法,记录到数据库.这样设计有明显的不足:1.log方法 ...

  4. jdk动态代理源码学习

    最近用到了java的动态代理,虽然会用,但不了解他具体是怎么实现,抽空看看了看他的源码. 说到Java的动态代理就不能不说到代理模式,动态代理也就是多了一个'动态'两字,在<大话设计模式> ...

  5. Java动态代理源码详解

    一.概述   前言:本文除了讲解JDK动态代理及CGLIB动态代理实例和应用外,还会讲解JDK动态代理源码实现过程以及自己写一手个JDK动态代理等.   动态代理在很多底层框架中都会用得到,比如在Sp ...

  6. 动态代理及JDK代理源码解析

    动态代理及JDK代理源码解析 参考:JDK动态代理-超详细源码分析 - 简书 (jianshu.com) 文章目录 动态代理及JDK代理源码解析 一.为什么需要动态代理 什么是代理模式? 静态代理: ...

  7. javabean反射改字段内容_BAT程序员编写:深入理解 Java 反射和动态代理源码分析...

    什么是反射 反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. 通过反射机制,可以在运行时访问 Java ...

  8. 动态代理源码分析,实现自己的动态代理

    什么是代理 增强一个对象的功能 买火车票,app就是一个代理,他代理了火车站,小区当中的代售窗口 java当中如何实现代理 java实现的代理的两种办法 代理的名词 代理对象 增强后的对象 目标对象 ...

  9. Android动态代理源码分析

    前言 前面我们简单介绍了代理模式的使用Android设计模式详解之代理模式,我们也明白了动态代理模式的重要性,那动态代理究竟是如何实现将方法交给InvocationHandler.invoke执行的呢 ...

最新文章

  1. Nacos客户端配置
  2. android语法帮助手册_新 App 「捧读:日语语法学习与分析」的开发幕后思考
  3. spring—拦截器和异常
  4. LintCode 1753. 写作业(二分查找)
  5. ImportError: cannot import name ‘Optional‘
  6. Python实战之多线程编程thread模块
  7. 中的live_2016知乎Live精选汇编——简历类
  8. Flutter之路由系列之Route
  9. 龙蜥操作系统(Anolis OS)正式登陆阿里云公共云
  10. 面试软件测试的时候,应届生怎么包装自己的简历?
  11. 逻辑删除(通俗易懂)
  12. 普法Android.mk中的一些宏和Android.bp对应关系
  13. 如何在Word2010中查找指定文字
  14. 水泥路面、桥梁基建、隧道裂痕裂缝检测数据集
  15. Pap.er 3.5.4 中文版 (专为Mac设计的高清壁纸应用)
  16. webofscience入口注册_Web of Science科研数据库平台
  17. 【GTSAM】GTSAM/iSAM1/2资源整理
  18. 芦荟妙用(摘自网络)
  19. 软件评测师——操作系统
  20. 计算机考研经验贴-初试

热门文章

  1. (附超声射频数据)matlab实现b超原始信号数据生成图像
  2. iOS使用UICollectionView只允许向左方向滑动,不允许向右方向滑动。
  3. 抖音无水印视频批量下载
  4. RoI Pooling 和 RoI Align
  5. 阿里云服务器+微信公众号配置(Token验证不通过)
  6. 半年亏损超5亿美元/股价腰斩,这家自动驾驶公司日子不好过
  7. 中国虚拟人哪家强?沙利文、IDC:小冰百度商汤位列第一梯队
  8. 用for循环写520个我喜欢你
  9. 如何通过热点打造爆款笔记?6个好写易爆的热点类型
  10. AutoJs学习-包名查看器