cglib

ASM是一个非常高效的Java字节码操控和分析框架,它允许开发者在运行时或者编译时期动态地生成、改变或者分析类。ASM提供的功能强大且灵活,适用于诸如框架开发、代码优化、代码生成等多种场景

需求:用 asm 编写一个类并运行输出hello word

依赖

<dependency>

    <groupId>org.ow2.asm</groupId>

    <artifactId>asm</artifactId>

    <version>9.1</version>

</dependency>

public static void main(String[] args) throws Exception {

         // 类名,包括包名,这里简化处理,不指定包名
        String className = "com.asm.test.ExampleClass";
        String fullName = className.replace('.', '/'); // 将点换成斜杠,因为ASM内部使用的是内部类名表示法

        // 创建ClassWriter对象,用于生成字节码
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        // 定义类,public class ExampleClass
        cw.visit(Opcodes.V1_8, // Java版本号,这里是Java 8
                Opcodes.ACC_PUBLIC, // 类访问修饰符,这里是public
                fullName, // 类名
                null, // 类签名,这里省略
                "java/lang/Object", // 父类,这里是Object
                null); // 实现的接口,这里没有实现任何接口

        // 添加默认构造函数
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载this引用
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); // 调用父类构造函数
        mv.visitInsn(Opcodes.RETURN); // 返回
        mv.visitMaxs(1, 1); // 设置最大栈和局部变量大小,这里简化处理
        mv.visitEnd();

        // 添加sayHello()方法
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "sayHello", "()V", null, null);
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitLdcInsn("Hello, World!"); // 将字符串常量推入栈顶
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); // 调用println方法
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(2, 1); // 设置最大栈和局部变量大小
        mv.visitEnd();

        // 结束类定义
        cw.visitEnd();

        // 生成字节码到文件
        byte[] code = cw.toByteArray();
        FileOutputStream fos = new FileOutputStream("target/classes/"+fullName + ".class");
        fos.write(code);
        fos.close();

        System.out.println("Generated class file: " + className + ".class");
        // 加载ExampleClass
        Class<?> exampleClass = Class.forName(className); // 注意这里的类名不需要加.class
        
        // 创建ExampleClass的实例
        Object instance = exampleClass.getDeclaredConstructor().newInstance();
        
        // 获取sayHello方法
        Method sayHelloMethod = exampleClass.getMethod("sayHello");
        
        // 调用sayHello方法
        sayHelloMethod.invoke(instance);

    }

CGlib (Code Generation Library) 是一个强大的高性能的代码生成库,它为Java语言提供了一个非常便利的API来扩展Java类与实现接口。不同于ASM库直接操作字节码,CGlib采取了更高层次的抽象,使得开发者可以以面向对象的方式创建代理类或者子类,而无需了解底层字节码的细节。CGlib主要用于以下几个场景:

  1. 动态代理:当不能使用Java原生的java.lang.reflect.Proxy(仅能代理实现了接口的类)时,CGlib可以创建目标类的子类作为代理,因此适用于没有实现接口的类的增强。

  2. AOP(面向切面编程):在AOP框架中,如Spring AOP,默认情况下使用JDK动态代理,但若目标对象没有实现接口,则转而使用CGlib来创建代理对象,实现在方法前后插入自定义逻辑(如日志记录、事务管理等)。

  3. 持久化框架:一些ORM(对象关系映射)框架,如Hibernate的动态代理功能,可能会用到CGlib来实现延迟加载等特性。

  4. 其他框架与库:许多Java应用框架,如Spring、MyBatis等,都可能间接使用CGlib来增强或代理对象。

使用cglib创建代理

依赖

    <dependency>

        <groupId>cglib</groupId>

        <artifactId>cglib</artifactId>

        <version>3.3.0</version>

    </dependency>


public class CGlibProxyExample implements MethodInterceptor {

    public Object getProxy(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        // enhancer.setInterfaces(new Class[]{SomeInterface.class});
        // 设置回调方法
        enhancer.setCallback(this);
        // 创建并返回代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method execution");
        Object result = proxy.invokeSuper(obj, args); // 调用原始方法
        System.out.println("After method execution");
        return result;
    }

    public static void main(String[] args) {
        CGlibProxyExample example = new CGlibProxyExample();
        SomeService proxy = (SomeService) example.getProxy(SomeService.class);
        proxy.doSomething();
        // ((SomeInterface)proxy).doOtherSomething();
    }
}

public class SomeService {
    public void doSomething() {
        System.out.println("do something exe");
    }
}

### CGLIB 的功能 CGLIB(Code Generation Library)是一个强大的字节码生成库,能够在运行时动态地生成目标类的子类,从而实现代理功能。其核心功能是通过继承目标类来创建代理对象,因此可以用于对没有实现接口的类进行代理。与 JDK 动态代理不同,CGLIB 不依赖接口,而是通过操作字节码来实现对类的增强。 CGLIB 的代理机制主要依赖于 `Enhancer` 类,它能够为指定的类创建子类,并在子类中拦截对父类方法的调用,从而实现诸如日志记录、事务管理等功能。CGLIB 还使用了 `FastClass` 机制,使得方法调用的性能优于传统的反射调用[^3]。 --- ### CGLIB 的使用场景 CGLIB 的使用场景主要包括以下几种情况: - **目标类没有实现接口**:JDK 动态代理要求目标类必须实现至少一个接口,而 CGLIB 可以对任意类进行代理,因此在目标类未实现接口时,CGLIB 是唯一的选择。 - **需要代理非接口方法**:CGLIB 通过继承机制代理类中的方法,因此可以代理非接口定义的方法。 - **需要代理 final 类或方法时**:虽然 CGLIB 无法代理 `final` 类或 `final` 方法,但在某些特定场景下,可以通过配置或修改类结构来规避这一限制。 - **需要更高的性能**:CGLIB 的 `FastClass` 机制避免了反射调用的开销,因此在对性能要求较高的场景下,CGLIB 比 JDK 动态代理更具优势[^1]。 - **强制使用基于类的代理**:在 Spring 配置中,可以通过设置 `proxy-target-class="true"` 强制使用 CGLIB 代理,即使目标类实现了接口。 --- ### CGLIB 与 Spring 的关系 Spring 框架广泛使用 CGLIB 来实现 AOP(面向切面编程)功能。Spring AOP 默认使用 JDK 动态代理,但当目标对象没有实现任何接口时,Spring 会自动切换到 CGLIB 代理。此外,Spring 允许通过配置强制使用 CGLIB 代理,以确保代理逻辑的一致性。 Spring 在内部通过 `Enhancer` 类创建代理对象,并结合 `MethodInterceptor` 接口来拦截方法调用。Spring AOP 利用 CGLIB 的字节码增强能力,在方法调用前后插入切面逻辑,例如事务管理、日志记录等。 Spring Boot 2.x 中默认使用 CGLIB 而不再使用 JDK 动态代理,主要是因为 CGLIB 的灵活性和性能优势。JDK 动态代理依赖于接口,而 Spring Boot 的设计倾向于更通用的代理方式,CGLIB 能够满足这一需求。 --- ### 示例代码:使用 CGLIB 创建代理 ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxyExample { static class TargetClass { public void sayHello() { System.out.println("Hello from target class!"); } } static class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("After method: " + method.getName()); return result; } } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new MyMethodInterceptor()); TargetClass proxy = (TargetClass) enhancer.create(); proxy.sayHello(); } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值