jdk和cglib简单理解(转)

简介:  之前使用cglib的时候不需要将classLoader作为参数传入,但动态代理却要,带着这个疑惑进入这个方法:   Proxy.newProxyInstance(classLoader, interfaces, InvocationHandler)   要在classLoader里去找interfaces,如果也加载进来了才能继续执行,并且用ProxyGenerator动态生成了一个代理类的字节码文件(使用了缓存技术,只需要生成一次),然后用classLoader将这个字节码文件加载进来。

 之前使用cglib的时候不需要将classLoader作为参数传入,但动态代理却要,带着这个疑惑进入这个方法:

  Proxy.newProxyInstance(classLoader, interfaces, InvocationHandler)

  要在classLoader里去找interfaces,如果也加载进来了才能继续执行,并且用ProxyGenerator动态生成了一个代理类的字节码文件(使用了缓存技术,只需要生成一次),然后用classLoader将这个字节码文件加载进来。这就是classLoader的作用。

  可以这样看生成的字节码类。

  加入执行参数:

  System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true") 

  生成的字节码文件就会保留下来,然后编译出来如下:

复制代码
package demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements IA {
  private static Method m1;
  private static Method m4;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  public $Proxy0(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject) {
    try {
      return ((Boolean) this.h.invoke(this, m1, 
          new Object[] { paramObject })).booleanValue();
    } catch (RuntimeException localRuntimeException) {
      throw localRuntimeException;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int b(String paramString) {
    try {
      return ((Integer) this.h.invoke(this, m4,
           new Object[] { paramString })).intValue();
    } catch (RuntimeException localRuntimeException) {
      throw localRuntimeException;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void a() {
    try {
      this.h.invoke(this, m3, null);
      return;
    } catch (RuntimeException localRuntimeException) {
      throw localRuntimeException;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode() {
    try {
      return ((Integer) this.h.invoke(this, m0, null)).intValue();
    } catch (RuntimeException localRuntimeException) {
      throw localRuntimeException;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString() {
    try {
      return (String) this.h.invoke(this, m2, null);
    } catch (RuntimeException localRuntimeException) {
      throw localRuntimeException;
    } catch (Throwable localThrowable) {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static {
    try {
      m1 = Class.forName("java.lang.Object").getMethod("equals",
          new Class[] { Class.forName("java.lang.Object") });
      m4 = Class.forName("demo.IA").getMethod("b", 
          new Class[] { Class.forName("java.lang.String") });
      m3 = Class.forName("demo.IA").getMethod("a", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    } catch (NoSuchMethodException localNoSuchMethodException) {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    } catch (ClassNotFoundException localClassNotFoundException) {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}
复制代码

可以发现所有接口方法的实现都委托给InvocationHandler的invoke方法了,这也就是实现代理模式的地方了。

 

--------------------------------------------------------------------------

cglib不需要传入ClassLoader,代码里会自己去找上下文的ClassLoader,这种设计使少传一个ClassLoader这种很少见的参数对初学者来说用起来要简单点。

可以设置System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "字节码文件保存位置",把cglib生成的动态字节码保存下来。

单间分析下生成的字节码

动态生成的继承类会改写我们使用的父类的所有方法,拦截下来交给设置的MethodInterceptor去执行。

  public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy)

第一个参数obj就是动态生成的子类。第二个参数是原始类的方法。

  我们一般使用proxy.invokeSuper(obj,args)方法。这个很好理解,就是执行原始类的方法。还有一个方法proxy.invoke(obj,args),这是执行生成子类的方法。如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不挺地进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。

  我们来看看MethodProxy,原始类里每一个方法都会在动态的子类里有一个对应的MethodProxy,而一个MethodProxy又对应了两个动态生成的FastClass类,一个是对应原始方法,一个对应新生成的子类,MethodProxy.invokeSuper就是交给对应原始方法那个FastClass,MethodProxy.invoke交给另一个。

  这2个额外生成的类作用在于当我们调用一个方法时,不通过反射来调用,而是通过类似于数组下标的方式来定位方法,直接进行类方法的执行。

  FastClass生成的代码类似这样的

public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)
    throws InvocationTargetException
  {
    // Byte code:
       0: aload_2 
       1: checkcast 159	net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df
       4: iload_1   //paramInt参数入栈
       5: tableswitch	default:+403 -> 408, 0:+131->136..... //通过paramInt也就相当于数组小标志,定位到方法执行的代码段
.....
.....
       148: aload_3
       149: iconst_0
       150: aaload
       151: invokevirtual 166	net/sf/cglib/mytest/A$$EnhancerByCGLIB$$f84d7df:equals	(Ljava/lang/Object;)Z //直接快速的执行方法
.....
.....
  }
}
http://www.cnblogs.com/onlywujun/p/3524690.html



相关文章
|
3月前
|
Java Spring
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: ● JDK动态代理只提供接口的代理,不支持类的代理Proxy.newProxyInstance(类加载器, 代理对象实现的所有接口, 代理执行器) ● CGLIB是通过继承的方式做的动态代理 , 如果某个类被标记为final,那么它是无法使用 CGLIB做动态代理的。Enhancer.create(父类的字节码对象, 代理执行器)
|
3月前
|
监控 Java API
JDK动态代理和CGLIB动态代理
Java动态代理允许在运行时创建代理对象,增强或拦截目标类方法的执行。主要通过两种方式实现:JDK动态代理和CGLIB动态代理。JDK动态代理基于接口,利用`java.lang.reflect.Proxy`类和`InvocationHandler`接口;CGLIB则通过字节码技术生成目标类的子类作为代理,适用于未实现接口的类。两者均用于在方法执行前后添加额外逻辑,如日志记录、权限控制等,广泛应用于AOP框架中。
103 2
|
4月前
|
监控 Java API
JDK动态代理和CGLIB动态代理
Java动态代理允许在运行时创建代理对象,增强或拦截目标类的方法调用,无需修改原代码。它有两种主要实现方式:JDK动态代理和CGLIB动态代理。 - **JDK动态代理**:通过`java.lang.reflect.Proxy`类和`InvocationHandler`接口实现,适用于实现了接口的类。它在方法调用前后插入额外逻辑,如日志记录、权限控制等。 - **CGLIB动态代理**:基于字节码技术,为未实现接口的类生成子类作为代理,重写父类方法以添加增强逻辑。适用于没有接口的类,但要求目标类不能是`final`类或方法。
|
4月前
|
Java API 数据安全/隐私保护
探索Java动态代理的奥秘:JDK vs CGLIB
动态代理是一种在 运行时动态生成代理类的技术,无需手动编写代理类代码。它通过拦截目标方法的调用,实现对核心逻辑的 无侵入式增强(如日志、事务、权限控制等)。
112 0
探索Java动态代理的奥秘:JDK vs CGLIB
|
7月前
|
安全 Java 开发者
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战模拟
【11月更文挑战第21天】面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(cross-cutting concerns)与业务逻辑分离,以提高代码的可维护性和可重用性。在Java开发中,AOP的实现离不开动态代理技术,其中JDK动态代理和CGLIB动态代理是两种常用的方式。本文将从背景、历史、功能点、业务场景、底层逻辑等多个维度,深度解析这两种代理方式的区别,并通过Java示例进行模拟和比较。
505 5
|
8月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
93 1
|
10月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
751 0
|
10月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
333 0
|
12月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
57 0
|
12月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
59 0