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 ExampleClasscw.visit(Opcodes.V1_8, // Java版本号,这里是Java 8Opcodes.ACC_PUBLIC, // 类访问修饰符,这里是publicfullName, // 类名null, // 类签名,这里省略"java/lang/Object", // 父类,这里是Objectnull); // 实现的接口,这里没有实现任何接口// 添加默认构造函数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");// 加载ExampleClassClass<?> 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主要用于以下几个场景:
-
动态代理:当不能使用Java原生的
java.lang.reflect.Proxy
(仅能代理实现了接口的类)时,CGlib可以创建目标类的子类作为代理,因此适用于没有实现接口的类的增强。 -
AOP(面向切面编程):在AOP框架中,如Spring AOP,默认情况下使用JDK动态代理,但若目标对象没有实现接口,则转而使用CGlib来创建代理对象,实现在方法前后插入自定义逻辑(如日志记录、事务管理等)。
-
持久化框架:一些ORM(对象关系映射)框架,如Hibernate的动态代理功能,可能会用到CGlib来实现延迟加载等特性。
-
其他框架与库:许多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();}@Overridepublic 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");}
}