Java反射与动态代理
一、Java反射
1.1 反射的概念
反射是 Java 提供的一种强大机制,它允许程序在运行时动态地获取类的信息,包括类的属性、方法、构造函数等,并且可以在运行时创建对象、调用方法、访问和修改属性。通过反射,程序可以在运行时根据需要操作类,而不是在编译时就确定好所有的操作。
1.2 反射的主要用途
- 框架开发:许多 Java 框架(如 Spring、Hibernate 等)大量使用反射机制来实现依赖注入、对象创建和方法调用等功能。
- 插件化开发:可以在运行时动态加载和使用外部的类和方法。
- 调试和测试工具:用于检查和修改程序的状态。
1.3 反射的关键类和方法
Class类:是反射的核心类,代表一个类的运行时信息。可以通过以下几种方式获取Class对象:- 类名.class:例如
Class<?> clazz = String.class; - 对象.getClass():例如
String str = "hello"; Class<?> clazz = str.getClass(); - Class.forName():例如
Class<?> clazz = Class.forName("java.lang.String");
- 类名.class:例如
Constructor类:用于表示类的构造函数,可以通过Class对象的getConstructors()或getDeclaredConstructors()方法获取构造函数数组,然后使用newInstance()方法创建对象。Method类:用于表示类的方法,可以通过Class对象的getMethods()或getDeclaredMethods()方法获取方法数组,然后使用invoke()方法调用方法。Field类:用于表示类的属性,可以通过Class对象的getFields()或getDeclaredFields()方法获取属性数组,然后使用get()和set()方法访问和修改属性值。
1.4 反射示例代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");
}
}
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> clazz = Person.class;
// 创建对象
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Person person = (Person) constructor.newInstance("John", 25);
// 调用方法
Method sayHelloMethod = clazz.getMethod("sayHello");
sayHelloMethod.invoke(person);
// 访问和修改属性
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 设置为可访问私有属性
nameField.set(person, "Mike");
Method getNameMethod = clazz.getMethod("getName");
System.out.println("New name: " + getNameMethod.invoke(person));
}
}
1.5 反射的优缺点
- 优点:提供了高度的灵活性和动态性,使得程序可以在运行时根据需要进行调整。
- 缺点:性能相对较低,因为反射涉及到大量的动态查找和调用;安全性较低,因为可以绕过访问控制修饰符访问和修改私有成员。
二、Java动态代理
2.1 动态代理的概念
动态代理是一种在运行时创建代理对象的机制,它允许在不修改目标对象代码的情况下,对目标对象的方法进行增强。代理对象会拦截对目标对象方法的调用,并在调用前后添加额外的逻辑。
2.2 动态代理的主要用途
- AOP(面向切面编程):在 Spring 框架中,动态代理被广泛用于实现 AOP,如日志记录、事务管理等。
- 远程方法调用(RMI):在分布式系统中,动态代理可以用于实现远程方法调用。
2.3 Java 中的动态代理实现方式
2.3.1 JDK 动态代理
- 原理:基于接口实现,通过
java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。 - 示例代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
interface Subject {
void request();
}
// 目标对象
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 调用处理器
class ProxyHandler implements InvocationHandler {
private Object target;
public ProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method call");
Object result = method.invoke(target, args);
System.out.println("After method call");
return result;
}
}
public class JdkDynamicProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxyHandler handler = new ProxyHandler(realSubject);
Subject proxySubject = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(),
new Class<?>[]{Subject.class},
handler
);
proxySubject.request();
}
}
2.3.2 CGLIB 动态代理
- 原理:基于继承实现,通过生成目标类的子类来实现代理。它可以对没有实现接口的类进行代理。
- 示例代码(需要引入 CGLIB 依赖)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 目标类
class TargetClass {
public void doSomething() {
System.out.println("TargetClass: Doing something.");
}
}
// 方法拦截器
class CglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method call");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method call");
return result;
}
}
public class CglibDynamicProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new CglibInterceptor());
TargetClass proxy = (TargetClass) enhancer.create();
proxy.doSomething();
}
}
2.4 动态代理的优缺点
- 优点:可以在不修改目标对象代码的情况下,对目标对象的方法进行增强,提高了代码的可维护性和可扩展性。
- 缺点:JDK 动态代理只能对实现了接口的类进行代理;CGLIB 动态代理由于是基于继承实现,可能会存在一些性能开销。
315

被折叠的 条评论
为什么被折叠?



