改进 visitMethod 方法,增加对构造函数的处理:
- public MethodVisitor visitMethod(final int access, final String name,
- final String desc, final String signature, final String[] exceptions) {
- MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
- MethodVisitor wrappedMv = mv;
- if (mv != null) {
- if (name.equals("operation")) {
- wrappedMv = new AddSecurityCheckMethodAdapter(mv);
- } else if (name.equals("<init>")) {
- wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
- enhancedSuperName);
- }
- }
- return wrappedMv;
- }
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
MethodVisitor wrappedMv = mv;
if (mv != null) {
if (name.equals("operation")) {
wrappedMv = new AddSecurityCheckMethodAdapter(mv);
} else if (name.equals("<init>")) {
wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,
enhancedSuperName);
}
}
return wrappedMv;
}
这里 ChangeToChildConstructorMethodAdapter 将负责把 Account 的构造函数改造成其子类 Account$EnhancedByASM 的构造函数:
- class ChangeToChildConstructorMethodAdapter extends MethodAdapter {
- private String superClassName;
- public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,
- String superClassName) {
- super(mv);
- this.superClassName = superClassName;
- }
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc) {
- //调用父类的构造函数时
- if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
- owner = superClassName;
- }
- super.visitMethodInsn(opcode, owner, name, desc);//改写父类为superClassName
- }
- }
class ChangeToChildConstructorMethodAdapter extends MethodAdapter {
private String superClassName;
public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,
String superClassName) {
super(mv);
this.superClassName = superClassName;
}
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
//调用父类的构造函数时
if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {
owner = superClassName;
}
super.visitMethodInsn(opcode, owner, name, desc);//改写父类为superClassName
}
}
最后演示一下如何在运行时产生并装入产生的 Account$EnhancedByASM。 我们定义一个 Util 类,作为一个类工厂负责产生有安全检查的 Account 类:
- public class SecureAccountGenerator {
- private static AccountGeneratorClassLoader classLoader =
- new AccountGeneratorClassLoade();
- private static Class secureAccountClass;
- public Account generateSecureAccount() throws ClassFormatError,
- InstantiationException, IllegalAccessException {
- if (null == secureAccountClass) {
- ClassReader cr = new ClassReader("Account");
- ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);
- cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
- byte[] data = cw.toByteArray();
- secureAccountClass = classLoader.defineClassFromClassFile(
- "Account$EnhancedByASM",data);
- }
- return (Account) secureAccountClass.newInstance();
- }
- private static class AccountGeneratorClassLoader extends ClassLoader {
- public Class defineClassFromClassFile(String className,
- byte[] classFile) throws ClassFormatError {
- return defineClass("Account$EnhancedByASM", classFile, 0, classFile.length());
- |-------10--------20--------30--------40--------50--------60--------70--------80--------9|
- |-------- XML error: The previous line is longer than the max of 90 characters ---------|
- }
- }
- }
public class SecureAccountGenerator {
private static AccountGeneratorClassLoader classLoader =
new AccountGeneratorClassLoade();
private static Class secureAccountClass;
public Account generateSecureAccount() throws ClassFormatError,
InstantiationException, IllegalAccessException {
if (null == secureAccountClass) {
ClassReader cr = new ClassReader("Account");
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);
cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] data = cw.toByteArray();
secureAccountClass = classLoader.defineClassFromClassFile(
"Account$EnhancedByASM",data);
}
return (Account) secureAccountClass.newInstance();
}
private static class AccountGeneratorClassLoader extends ClassLoader {
public Class defineClassFromClassFile(String className,
byte[] classFile) throws ClassFormatError {
return defineClass("Account$EnhancedByASM", classFile, 0, classFile.length());
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
}
}
}
静态方法 SecureAccountGenerator.generateSecureAccount() 在运行时动态生成一个加上了安全检查的 Account 子类。著名的 Hibernate 和 Spring 框架,就是使用这种技术实现了 AOP 的“无损注入”。
小结
最后,我们比较一下 ASM 和其他实现 AOP 的底层技术:
表 1. AOP 底层技术比较
AOP 底层技术 功能 性能 面向接口编程 编程难度
直接改写 class 文件 完全控制类 无明显性能代价 不要求 高,要求对 class 文件结构和 Java 字节码有深刻了解
JDK Instrument 完全控制类 无论是否改写,每个类装入时都要执行hook程序 不要求 高,要求对 class 文件结构和 Java 字节码有深刻了解
JDK Proxy 只能改写 method 反射引入性能代价 要求 低
ASM 几乎能完全控制类 无明显性能代价 不要求 中,能操纵需要改写部分的 Java 字节码