Java反射与代理:解锁框架底层原理(附实战示例)
·
作为Java后端开发者,掌握反射与代理是理解Spring、MyBatis等框架底层原理的关键。下面我将用清晰结构+可运行示例+框架关联的方式为你系统讲解。
一、反射机制(Reflection)—— “运行时窥探与操控类”
🔍 核心概念
反射允许程序在运行时动态获取类信息、创建对象、调用方法、访问字段(包括私有成员),打破编译期限制。
📌 获取Class对象的3种方式
// 1. 通过Class.forName(会触发静态初始化)
Class<?> clazz1 = Class.forName("java.util.ArrayList");
// 2. 通过对象的getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();
// 3. 通过类字面量(最安全高效,推荐)
Class<ArrayList> clazz3 = ArrayList.class;
💡 完整实战示例:操作私有成员
// 定义测试类
class User {
private String name;
private int age;
public User(String name) { this.name = name; } // 仅有一个构造参数
private void introduce() {
System.out.println("I'm " + name + ", " + age + " years old");
}
}
// 反射操作
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
// 1. 创建对象(绕过private构造)
Constructor<User> constructor = userClass.getDeclaredConstructor(String.class);
constructor.setAccessible(true); // 禁用访问检查
User user = constructor.newInstance("张三");
// 2. 修改私有字段
Field ageField = userClass.getDeclaredField("age");
ageField.setAccessible(true);
ageField.setInt(user, 25);
// 3. 调用私有方法
Method introMethod = userClass.getDeclaredMethod("introduce");
introMethod.setAccessible(true);
introMethod.invoke(user);
// 输出:I'm 张三, 25 years old
}
}
✅ 应用场景
- Spring IoC:
@Autowired通过反射注入依赖 - ORM框架:MyBatis通过反射将ResultSet映射为Java对象
- JUnit:通过反射查找并执行
@Test注解的方法 - 序列化库:Gson/Jackson反射读取字段生成JSON
⚠️ 注意事项
|
问题 |
说明 |
|---|---|
|
性能开销 |
反射调用比直接调用慢2-3倍(现代JVM已优化,但高频场景仍需谨慎) |
|
破坏封装 |
|
|
异常风险 |
编译期无法检查,易抛 |
|
泛型擦除 |
运行时无法直接获取泛型具体类型(需通过父类ParameterizedType技巧) |
二、代理机制(Proxy)—— “为对象添加增强逻辑”
🌐 代理模式核心思想
为真实对象提供一个替身,在不修改原对象代码的前提下,增加额外功能(如日志、事务、权限校验)。
📐 两种代理实现方式对比
|
特性 |
静态代理 |
JDK动态代理 |
CGLIB动态代理 |
|---|---|---|---|
|
实现时机 |
编译期手写 |
运行时生成 |
运行时生成字节码 |
|
要求 |
需实现相同接口 |
必须有接口 |
可代理类(无需接口) |
|
原理 |
手动编码 |
|
继承目标类+字节码增强 |
|
性能 |
高(无反射) |
中(方法调用用反射) |
高(FastClass机制) |
|
限制 |
代码冗余 |
不能代理final类/方法 |
不能代理final类/方法 |
|
典型应用 |
简单场景 |
Spring AOP(默认) |
Spring AOP(无接口时) |
🧪 示例1:JDK动态代理(基于接口)
// 1. 定义接口
public interface PaymentService {
boolean pay(String orderId, double amount);
}
// 2. 真实实现
public class AlipayService implements PaymentService {
public boolean pay(String orderId, double amount) {
System.out.println("Alipay processing: " + orderId + " ¥" + amount);
return true;
}
}
// 3. 代理处理器(核心!)
public class LogInvocationHandler implements InvocationHandler {
private final Object target;
public LogInvocationHandler(Object target) { this.target = target; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【前置】调用方法: " + method.getName() + ", 参数: " + Arrays.toString(args));
long start = System.currentTimeMillis();
Object result = method.invoke(target, args); // 反射调用真实方法
long cost = System.currentTimeMillis() - start;
System.out.println("【后置】方法返回: " + result + ", 耗时: " + cost + "ms");
return result;
}
}
// 4. 使用
public class JdkProxyDemo {
public static void main(String[] args) {
PaymentService realService = new AlipayService();
PaymentService proxy = (PaymentService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new LogInvocationHandler(realService)
);
proxy.pay("ORDER_2026", 99.9);
// 输出包含日志、耗时等增强逻辑
}
}
🧪 示例2:CGLIB动态代理(无接口场景)
// 1. 无接口的类
public class UserService {
public String getUserInfo(String userId) {
return "User-" + userId;
}
}
// 2. 方法拦截器
public class ServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB【拦截】: " + method.getName());
return proxy.invokeSuper(obj, args); // 调用父类(真实对象)方法
}
}
// 3. 使用(需添加Maven依赖:net.sf.cglib:cglib:3.3.0)
public class CglibDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new ServiceInterceptor());
UserService proxy = (UserService) enhancer.create();
System.out.println(proxy.getUserInfo("U1001"));
// 输出:CGLIB【拦截】: getUserInfo + User-U1001
}
}
🔗 反射与代理的关系 & 框架实战
💡 核心关联
- 动态代理的基石是反射:JDK代理中
InvocationHandler.invoke()内部通过反射调用目标方法;CGLIB在生成字节码时也依赖反射获取方法信息。 - 反射 ≠ 代理:反射是语言特性(能力),代理是设计模式(应用)。代理常借助反射实现动态性。
🌱 Spring框架中的经典应用
@Service
public class OrderService {
@Autowired
private PaymentService paymentService; // 1. 反射注入依赖
@Transactional // 2. Spring通过动态代理(JDK/CGLIB)为该方法添加事务控制
public void createOrder() {
paymentService.pay(...);
}
}
- 依赖注入:Spring通过反射读取
@Autowired注解,实例化并注入Bean - AOP实现:
- 若
OrderService实现接口 → 使用JDK动态代理 - 若未实现接口(或Spring Boot 2.0+)→ 默认使用CGLIB代理
- 代理对象在方法执行前后插入事务、日志等逻辑
- 若
💡 关键总结:反射赋予Java“动态能力”,代理模式利用这种能力实现“关注点分离”。掌握二者,你便拿到了通往框架设计世界的大门钥匙。建议结合Spring源码调试加深理解
更多推荐




所有评论(0)