面试题答案
一键面试实际应用场景:AOP(面向切面编程)
在企业级开发中,AOP 是一种常用的编程范式,用于将横切关注点(如日志记录、事务管理、权限验证等)从业务逻辑中分离出来。通过反射与字节码操作的结合,可以在运行时动态地为目标类添加这些横切逻辑,而无需修改目标类的源代码。
利用反射获取类信息
假设我们有一个简单的Java类 UserService
:
public class UserService {
public void sayHello() {
System.out.println("Hello!");
}
}
使用反射获取类信息的代码如下:
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) {
try {
// 获取类对象
Class<?> userServiceClass = Class.forName("UserService");
// 获取类的所有方法
Method[] methods = userServiceClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Method: " + method.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在上述代码中,通过 Class.forName("UserService")
获取 UserService
的类对象,然后使用 getDeclaredMethods()
方法获取类中声明的所有方法。
通过字节码操作(以 Javassist 为例)对类进行增强
首先需要添加 Javassist 的依赖到项目的 pom.xml
中:
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>
下面是使用 Javassist 为 UserService
类动态添加新方法并修改已有方法逻辑的示例代码:
import javassist.*;
public class BytecodeEnhancementExample {
public static void main(String[] args) {
try {
// 获取类池
ClassPool classPool = ClassPool.getDefault();
// 获取类
CtClass ctClass = classPool.get("UserService");
// 添加新方法
CtMethod newMethod = CtNewMethod.make("public void newMethod() { System.out.println(\"This is a new method.\"); }", ctClass);
ctClass.addMethod(newMethod);
// 修改已有方法逻辑
CtMethod sayHelloMethod = ctClass.getDeclaredMethod("sayHello");
sayHelloMethod.setBody("{ System.out.println(\"Before enhanced.\"); $_ = $proceed(); System.out.println(\"After enhanced.\"); }");
// 生成新的类
Class<?> enhancedClass = ctClass.toClass();
// 创建实例并调用方法
Object instance = enhancedClass.newInstance();
Method newMethodRef = enhancedClass.getDeclaredMethod("newMethod");
newMethodRef.invoke(instance);
Method sayHelloMethodRef = enhancedClass.getDeclaredMethod("sayHello");
sayHelloMethodRef.invoke(instance);
} catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException | NoSuchMethodException | java.lang.reflect.InvocationTargetException e) {
e.printStackTrace();
}
}
}
在上述代码中,通过 Javassist 的 ClassPool
获取 UserService
类的 CtClass
对象。然后使用 CtNewMethod.make
方法创建一个新方法并添加到类中。对于已有方法 sayHello
,通过 setBody
方法修改其逻辑,在原逻辑前后添加打印语句。最后通过 toClass
方法生成新的类,并通过反射创建实例调用新添加的方法和修改后的方法。