面试题答案
一键面试实现思路
- 定义注解:首先定义一个自定义注解,用于标记需要插入自定义逻辑的方法。
- 注解解析器:编写注解解析器,扫描类中的注解,确定哪些方法需要进行字节码增强。
- 字节码增强:使用字节码操作库(如ASM或Javassist),在方法调用前后插入自定义逻辑。
- 性能优化:避免不必要的增强,缓存已经增强的类,减少重复操作。
- 兼容性:确保字节码操作库与目标Java版本兼容,测试不同环境下的运行情况。
关键代码片段(以Javassist为例)
- 定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomLogicAnnotation {
}
- 注解解析器
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class AnnotationParser {
public static List<Method> getAnnotatedMethods(Class<?> clazz) {
List<Method> methods = new ArrayList<>();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(CustomLogicAnnotation.class)) {
methods.add(method);
}
}
return methods;
}
}
- 字节码增强
import javassist.*;
public class BytecodeEnhancer {
public static byte[] enhanceClass(ClassPool classPool, Class<?> clazz) throws NotFoundException, CannotCompileException {
CtClass ctClass = classPool.get(clazz.getName());
List<Method> annotatedMethods = AnnotationParser.getAnnotatedMethods(clazz);
for (Method method : annotatedMethods) {
CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName());
ctMethod.insertBefore("{ System.out.println(\"Before method call\"); }");
ctMethod.insertAfter("{ System.out.println(\"After method call\"); }");
}
byte[] bytecode = ctClass.toBytecode();
ctClass.detach();
return bytecode;
}
}
- 使用示例
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class Agent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className != null && className.startsWith("your/package/name")) {
try {
ClassPool classPool = ClassPool.getDefault();
return BytecodeEnhancer.enhanceClass(classPool, Class.forName(className.replace("/", ".")));
} catch (Exception e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
});
}
}
上述代码展示了使用Javassist进行字节码增强结合注解解析的基本流程,通过定义注解、解析注解和字节码增强实现方法调用前后插入自定义逻辑,并通过代理机制在类加载时完成增强操作。在实际应用中,可根据具体需求进一步优化和完善。