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主要用于以下几个场景:
-
动态代理:当不能使用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();
}
@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");
}
}