Cglib和JDK动态代理实现技术详解

Spring AOP 中的代理对象是怎么创建出来的?

在Spring AOP中,代理对象是通过动态代理技术创建的。Spring AOP主要使用两种类型的代理:基于接口的代理(JDK动态代理)和基于类的代理(CGLIB动态代理)。

  1. JDK动态代理(基于接口的代理):
    JDK动态代理是通过Java自带的 java.lang.reflect.Proxy 类来创建代理对象的。对于实现了接口的目标类,Spring AOP会创建一个实现了目标接口的代理类。这个代理类会重写接口中的方法,并在方法前后插入切面逻辑。JDK动态代理只能代理接口,不能代理类。
  2. CGLIB动态代理(基于类的代理):
    CGLIB动态代理是通过CGLIB库来创建代理对象的。对于没有实现接口的目标类,Spring AOP会使用CGLIB动态生成一个目标类的子类作为代理类。这个子类会重写目标类中的方法,并在方法前后插入切面逻辑。CGLIB动态代理可以代理类,但不能代理被标记为 final 的类和方法。

在Spring AOP中,选择使用哪种代理方式取决于被代理的目标类是否实现了接口以及其他因素。您可以在配置中使用 proxyTargetClass 属性来指定使用基于类的代理。

总之,无论是JDK动态代理还是CGLIB动态代理,Spring都会自动创建代理对象并将切面逻辑织入目标对象的方法中,实现AOP功能。

Cglib动态代理技术实现细节

CGLIB(Code Generation Library)是一个基于字节码生成的类库,它能够在运行时动态生成目标类的子类作为代理对象。相比于JDK动态代理,CGLIB动态代理不要求目标类实现接口,可以代理普通的类。下面是CGLIB动态代理的大致实现过程:

  1. 选择代理的目标类:首先,选择要代理的目标类,这个目标类通常是没有实现接口的普通类。
  2. 生成子类:CGLIB通过生成目标类的子类来实现代理。它使用ASM库来操作字节码,创建一个新的类,继承目标类,并在子类中添加切面逻辑。
  3. 重写方法:CGLIB生成的子类会重写目标类中的方法,将切面逻辑插入到这些方法的前后。这就实现了在方法执行前后执行切面逻辑的功能。
  4. 创建代理对象:通过调用CGLIB提供的API,将生成的子类加载到JVM中,并创建实例作为代理对象。
  5. 代理调用:当代理对象的方法被调用时,实际上是调用了子类中重写的方法,从而执行了切面逻辑。

CGLIB动态代理的优势是它可以代理没有实现接口的类,同时不需要目标类实现任何接口,因此更灵活。然而,它也有一些限制,例如不能代理被标记为 final 的类和方法,以及某些JVM限制等。

CGLIB的底层使用了字节码操作库ASM来操作字节码,这也是其实现动态代理的核心技术。通过生成新的类并在其中插入切面逻辑,CGLIB实现了在运行时动态地创建代理对象。

cglib动态代理生成子类的技术细节

CGLIB(Code Generation Library)是通过使用字节码操作库ASM(Java字节码操控框架)来实现动态生成子类的。下面是CGLIB动态生成子类的一般技术细节:

  1. 目标类的信息提取:CGLIB首先会提取目标类的信息,包括类名、方法名、字段名、方法参数类型等。
  2. ASM字节码生成:CGLIB使用ASM库来生成新的字节码,ASM允许直接操作Java字节码,包括创建类、方法、字段等。在生成子类时,CGLIB会生成一个新的类,继承自目标类,并且包含额外的切面逻辑。
  3. 重写方法:生成的子类会重写目标类中的方法,并在这些方法中插入切面逻辑。CGLIB通过访问方法的字节码,将切面逻辑插入到方法的前后。
  4. 类加载和实例化:生成的子类字节码会被加载到JVM中,并通过反射或其他方式创建实例,作为代理对象。这样,在调用代理对象的方法时,实际上是调用了子类中重写的方法,从而执行了切面逻辑。

总体来说,CGLIB利用ASM库的字节码操作能力,在运行时创建了一个新的子类,该子类继承自目标类并包含切面逻辑。通过重写方法并在方法中插入切面逻辑,CGLIB实现了动态代理的功能。这种方式相对于JDK动态代理,更适合代理那些没有实现接口的类。

spring中默认使用的是jdk动态代理还是cglib

Spring中的默认动态代理机制是基于JDK动态代理。当被代理的类实现了接口时,Spring会使用JDK动态代理来生成代理对象。

但是,当被代理的类没有实现接口时,Spring会自动切换到使用CGLIB动态代理。这是因为CGLIB可以代理那些没有接口的类,通过创建子类来实现代理。

你也可以通过配置来明确选择使用哪种代理方式,例如,如果你希望强制使用CGLIB代理,可以在配置中设置相应的选项。

JDK动态代理实现动态代理的技术细节

JDK动态代理是通过Java的反射机制来实现的,主要涉及到两个核心类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler。

  1. Proxy类: JDK的Proxy类是用于创建代理对象的主要类。它提供了一个静态方法newProxyInstance,该方法接受三个参数:类加载器、代理类要实现的接口列表和InvocationHandler接口的实现。
  2. InvocationHandler接口: 该接口中只有一个方法invoke,用于处理代理对象方法的调用。在实际使用中,需要编写一个实现InvocationHandler接口的类,然后重写invoke方法来实现自定义的代理逻辑。

基本流程如下:

  1. 创建一个实现了InvocationHandler接口的类,重写invoke方法,定义代理逻辑。
  2. 使用Proxy.newProxyInstance方法创建代理对象,传入目标类的类加载器、实现的接口列表和InvocationHandler对象。
  3. 调用代理对象的方法时,实际会调用invoke方法,然后在invoke方法中执行自定义的代理逻辑,最终调用目标对象的方法。

以下是一个简化的示例:

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

interface MyInterface {
    void doSomething();
}

class MyTarget implements MyInterface {
    public void doSomething() {
        System.out.println("Target doing something.");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoking method.");
        Object result = method.invoke(target, args);
        System.out.println("After invoking method.");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface target = new MyTarget();
        MyInvocationHandler handler = new MyInvocationHandler(target);

        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );

        proxy.doSomething();
    }
}

在这个示例中,MyInvocationHandler实现了InvocationHandler接口,Main类创建了一个MyInterface的代理对象,当调用代理对象的doSomething方法时,实际会触发invoke方法,在其中添加了前后的逻辑。

jdk底层是使用什么技术动态生成子类的,请给出技术细节

在JDK动态代理中,底层使用了Java的字节码生成技术,主要依赖于java.lang.reflect.Proxy类。该类使用了Java的反射机制以及字节码操作库来动态生成代理类的字节码。具体来说,它使用了sun.misc.ProxyGenerator类来生成字节码。

以下是大致的技术细节:

  1. 接口定义: 要创建一个代理对象,首先需要有一个接口或一组接口来定义代理对象要实现的方法。
  2. Proxy类调用: 使用Proxy.newProxyInstance方法创建代理对象。这个方法接受三个参数:类加载器、代理类要实现的接口列表和InvocationHandler接口的实现。
  3. 生成字节码: 当调用Proxy.newProxyInstance时,JDK会生成一个新的类,这个类是代理类的字节码。生成字节码的过程中,使用了sun.misc.ProxyGenerator类,它利用字节码操作库生成字节码。这个类并不是官方公开支持的API,所以可能在不同的JDK版本中有差异。
  4. 加载类: 生成的字节码类会被类加载器加载到内存中。
  5. 实例化代理对象: 生成的字节码类被加载后,可以使用反射机制创建代理对象的实例。

整个过程中,字节码生成技术是核心,它允许在运行时动态创建代理类,并在其中插入所需的代理逻辑。字节码生成技术允许在不事先编写具体代理类的情况下创建代理对象,从而实现动态代理的功能。

需要注意的是,因为sun.misc.ProxyGenerator并不是官方公开支持的API,所以在某些情况下可能会受到限制,而且不同的JDK版本可能会有不同的实现细节。

你可能感兴趣的:(Java,java,开发语言)