Java反射与动态代理深入解析
2025.02.19
Java
9 min
3.5k 字
// 目录 · contents
引言
反射(Reflection)和动态代理(Dynamic
Proxy)是Java语言中最强大的元编程特性,也是Spring、MyBatis、Hibernate等主流框架的底层基石。反射让程序可以在运行时检查和操作类的结构,动态代理则允许在不修改目标代码的前提下对方法调用进行拦截和增强。
本文将系统性地讲解反射API的核心用法、JDK动态代理与CGLIB代理的实现原理,并深入分析Spring
AOP中的代理选择策略。
反射的核心概念
graph TD
ClassLoader[ClassLoader 加载字节码] --> ClassObj[Class 对象]
ClassObj --> Fields[Field 字段]
ClassObj --> Methods[Method 方法]
ClassObj --> Constructors[Constructor 构造器]
ClassObj --> Annotations[Annotation 注解]
ClassObj --> Interfaces[Interface 接口]
ClassObj --> SuperClass[SuperClass 父类]
Fields --> GetSet[get/set 字段值]
Methods --> Invoke[invoke 调用方法]
Constructors --> NewInstance[newInstance 创建实例]
style ClassObj fill:#e3f2fd
Java反射的一切操作都围绕java.lang.Class对象展开。每个类在JVM中有且仅有一个Class对象,它包含了该类的完整元信息。
反射API详解
获取Class对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class ReflectionBasics {
public static void main(String[] args) throws Exception { Class<String> clazz1 = String.class;
String str = "hello"; Class<? extends String> clazz2 = str.getClass();
Class<?> clazz3 = Class.forName("java.lang.String");
System.out.println(clazz1 == clazz2); System.out.println(clazz2 == clazz3); } }
|
操作Field、Method、Constructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| public class ReflectionAdvanced {
static class User { private Long id; private String name; private int age;
private User() {}
public User(Long id, String name, int age) { this.id = id; this.name = name; this.age = age; }
private String formatInfo() { return String.format("User{id=%d, name='%s', age=%d}", id, name, age); }
public String getName() { return name; } }
public static void main(String[] args) throws Exception { Class<User> clazz = User.class;
Constructor<User> privateConstructor = clazz.getDeclaredConstructor(); privateConstructor.setAccessible(true); User user = privateConstructor.newInstance();
Constructor<User> publicConstructor = clazz.getDeclaredConstructor( Long.class, String.class, int.class); User user2 = publicConstructor.newInstance(1L, "张三", 28);
Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(user, "李四"); System.out.println(nameField.get(user));
for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); System.out.printf("字段名: %s, 类型: %s, 值: %s%n", field.getName(), field.getType().getSimpleName(), field.get(user2)); }
Method formatInfo = clazz.getDeclaredMethod("formatInfo"); formatInfo.setAccessible(true); String info = (String) formatInfo.invoke(user2); System.out.println(info);
Method getName = clazz.getMethod("getName"); String name = (String) getName.invoke(user2); System.out.println(name); } }
|
实用工具:通用Bean拷贝器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
public class BeanCopier {
private static final Map<Class<?>, Map<String, Field>> FIELD_CACHE = new ConcurrentHashMap<>();
public static <S, T> T copyProperties(S source, Class<T> targetClass) { try { T target = targetClass.getDeclaredConstructor().newInstance(); copyProperties(source, target); return target; } catch (ReflectiveOperationException e) { throw new RuntimeException("Bean拷贝失败", e); } }
public static void copyProperties(Object source, Object target) { Map<String, Field> sourceFields = getFields(source.getClass()); Map<String, Field> targetFields = getFields(target.getClass());
for (Map.Entry<String, Field> entry : sourceFields.entrySet()) { String fieldName = entry.getKey(); Field sourceField = entry.getValue(); Field targetField = targetFields.get(fieldName);
if (targetField != null && targetField.getType().isAssignableFrom(sourceField.getType())) { try { targetField.set(target, sourceField.get(source)); } catch (IllegalAccessException e) { throw new RuntimeException("字段赋值失败: " + fieldName, e); } } } }
private static Map<String, Field> getFields(Class<?> clazz) { return FIELD_CACHE.computeIfAbsent(clazz, c -> { Map<String, Field> fieldMap = new LinkedHashMap<>(); Class<?> current = c; while (current != null && current != Object.class) { for (Field field : current.getDeclaredFields()) { field.setAccessible(true); fieldMap.putIfAbsent(field.getName(), field); } current = current.getSuperclass(); } return fieldMap; }); } }
|
JDK动态代理
JDK动态代理是Java标准库提供的代理机制,它要求目标对象必须实现接口。代理对象会实现相同的接口,并将方法调用委托给InvocationHandler。
sequenceDiagram
participant Client as 调用方
participant Proxy as 代理对象 $Proxy0
participant Handler as InvocationHandler
participant Target as 目标对象
Client->>Proxy: 调用接口方法
Proxy->>Handler: invoke(proxy, method, args)
Handler->>Handler: 前置增强(日志/鉴权等)
Handler->>Target: method.invoke(target, args)
Target-->>Handler: 返回结果
Handler->>Handler: 后置增强(日志/异常处理等)
Handler-->>Proxy: 返回最终结果
Proxy-->>Client: 返回结果
JDK动态代理实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| public interface UserService { User findById(Long id); List<User> findAll(); void save(User user); }
public class UserServiceImpl implements UserService { @Override public User findById(Long id) { return new User(id, "张三", 28); }
@Override public List<User> findAll() { return List.of(new User(1L, "张三", 28), new User(2L, "李四", 35)); }
@Override public void save(User user) { System.out.println("保存用户: " + user); } }
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target; private static final Logger log = LoggerFactory.getLogger(LoggingInvocationHandler.class);
public LoggingInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName(); String params = args == null ? "" : Arrays.toString(args);
log.info("[BEFORE] {} 参数: {}", methodName, params); long start = System.nanoTime();
try { Object result = method.invoke(target, args); long elapsed = (System.nanoTime() - start) / 1_000_000; log.info("[AFTER] {} 耗时: {}ms 返回: {}", methodName, elapsed, result); return result; } catch (InvocationTargetException e) { Throwable cause = e.getCause(); log.error("[ERROR] {} 异常: {}", methodName, cause.getMessage()); throw cause; } } }
public class ProxyFactory {
@SuppressWarnings("unchecked") public static <T> T createJdkProxy(T target) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LoggingInvocationHandler(target) ); }
public static void main(String[] args) { UserService realService = new UserServiceImpl(); UserService proxyService = createJdkProxy(realService);
User user = proxyService.findById(1L); } }
|
CGLIB代理
CGLIB(Code Generation
Library)通过生成目标类的子类来实现代理,因此不要求目标类实现接口,但无法代理final类和final方法。
graph TD
subgraph JDK动态代理
Interface[接口定义] --> ProxyClass["$Proxy0 实现接口"]
ProxyClass --> IH[InvocationHandler]
IH --> TargetA[目标对象]
end
subgraph CGLIB代理
TargetClass[目标类] --> SubClass["Target$$EnhancerByCGLIB 子类"]
SubClass --> MI[MethodInterceptor]
MI --> TargetB[目标对象<br/>通过super调用]
end
style Interface fill:#e3f2fd
style TargetClass fill:#fff3e0
CGLIB代理实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public class OrderService {
public Order createOrder(String productName, int quantity) { Order order = new Order(); order.setOrderNo(UUID.randomUUID().toString()); order.setProductName(productName); order.setQuantity(quantity); System.out.println("创建订单: " + order.getOrderNo()); return order; }
public final String getServiceName() { return "OrderService"; } }
public class TransactionInterceptor implements MethodInterceptor {
private static final Logger log = LoggerFactory.getLogger(TransactionInterceptor.class);
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { log.info("[TX] 开启事务"); try { Object result = proxy.invokeSuper(obj, args); log.info("[TX] 提交事务"); return result; } catch (Exception e) { log.error("[TX] 回滚事务, 原因: {}", e.getMessage()); throw e; } } }
public class CglibProxyFactory {
@SuppressWarnings("unchecked") public static <T> T createCglibProxy(Class<T> targetClass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetClass); enhancer.setCallback(new TransactionInterceptor()); return (T) enhancer.create(); }
public static void main(String[] args) { OrderService proxy = createCglibProxy(OrderService.class);
proxy.createOrder("iPhone", 1);
String name = proxy.getServiceName(); } }
|
多个拦截器的CallbackFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class MultiCallbackExample {
public static <T> T createProxy(Class<T> targetClass) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetClass);
Callback[] callbacks = { new TransactionInterceptor(), new LoggingInterceptor(), NoOp.INSTANCE }; enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(method -> { if (method.isAnnotationPresent(Transactional.class)) { return 0; } else if (method.getName().startsWith("find") || method.getName().startsWith("get")) { return 1; } return 2; });
return (T) enhancer.create(); } }
|
Spring AOP中的代理选择
Spring AOP会根据目标对象的特征自动选择代理策略:
flowchart TD
Start[Spring创建Bean] --> HasInterface{目标类是否<br/>实现了接口?}
HasInterface -->|是| CheckConfig{proxyTargetClass<br/>=true?}
HasInterface -->|否| CGLIB[使用CGLIB代理]
CheckConfig -->|否| JDK[使用JDK动态代理]
CheckConfig -->|是| CGLIB
JDK --> ProxyObj1[代理对象<br/>实现相同接口]
CGLIB --> IsFinal{目标类是final?}
IsFinal -->|否| ProxyObj2[代理对象<br/>目标类的子类]
IsFinal -->|是| Error[抛出异常<br/>无法代理]
style JDK fill:#e3f2fd
style CGLIB fill:#fff3e0
style Error fill:#ffcdd2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class AopConfig { }
@Aspect @Component public class PerformanceAspect {
private static final Logger log = LoggerFactory.getLogger(PerformanceAspect.class);
@Around("@annotation(com.example.annotation.Monitored)") public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable { String signature = joinPoint.getSignature().toShortString(); long start = System.nanoTime();
try { Object result = joinPoint.proceed(); long elapsed = (System.nanoTime() - start) / 1_000_000; log.info("{} 执行成功, 耗时 {}ms", signature, elapsed); return result; } catch (Throwable e) { long elapsed = (System.nanoTime() - start) / 1_000_000; log.error("{} 执行失败, 耗时 {}ms, 异常: {}", signature, elapsed, e.getMessage()); throw e; } } }
|
性能对比
反射和动态代理相比直接调用有性能开销,以下是关键数据和优化建议:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Benchmark) @Warmup(iterations = 5, time = 1) @Measurement(iterations = 10, time = 1) @Fork(2) public class ProxyBenchmark {
private UserService directService; private UserService jdkProxy; private UserService cglibProxy; private Method cachedMethod;
@Setup public void setup() throws Exception { directService = new UserServiceImpl();
jdkProxy = (UserService) Proxy.newProxyInstance( UserService.class.getClassLoader(), new Class[]{UserService.class}, (proxy, method, args) -> method.invoke(directService, args) );
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> methodProxy.invokeSuper(obj, args)); cglibProxy = (UserService) enhancer.create();
cachedMethod = UserService.class.getMethod("findById", Long.class); cachedMethod.setAccessible(true); }
@Benchmark public User directCall() { return directService.findById(1L); }
@Benchmark public User jdkProxyCall() { return jdkProxy.findById(1L); }
@Benchmark public User cglibProxyCall() { return cglibProxy.findById(1L); }
@Benchmark public User reflectionCall() throws Exception { return (User) cachedMethod.invoke(directService, 1L); } }
|
典型性能对比(数据仅供参考):
| 直接调用 |
~5 |
1x |
| 反射调用(缓存Method) |
~20 |
4x |
| JDK动态代理 |
~25 |
5x |
| CGLIB代理 |
~15 |
3x |
| 反射调用(未缓存) |
~500 |
100x |
性能优化建议
- 缓存反射对象:
Class.forName()、getMethod()、getDeclaredField()等调用代价高,结果应缓存复用。
- 使用
setAccessible(true):跳过访问权限检查可以显著提升反射调用速度。
- 优先使用MethodHandle:Java
7引入的
MethodHandle在JIT优化后性能接近直接调用。
- CGLIB的
MethodProxy.invokeSuper:比Method.invoke快,因为它直接调用生成的子类方法,避免了反射。
- 生产环境考虑编译时增强:如Lombok的
@Delegate、MapStruct等编译时代码生成方案,零运行时开销。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class MethodHandleExample {
private static final MethodHandle FIND_BY_ID;
static { try { MethodHandles.Lookup lookup = MethodHandles.lookup(); FIND_BY_ID = lookup.findVirtual( UserServiceImpl.class, "findById", MethodType.methodType(User.class, Long.class) ); } catch (NoSuchMethodException | IllegalAccessException e) { throw new ExceptionInInitializerError(e); } }
public static User callViaMethodHandle(UserServiceImpl service, Long id) throws Throwable { return (User) FIND_BY_ID.invoke(service, id); } }
|
总结
反射和动态代理是Java元编程的两大核心能力:
反射API提供了运行时类信息访问和动态调用的能力,是框架开发的基础。核心操作围绕Class、Field、Method、Constructor四个类展开。
JDK动态代理基于接口生成代理类,通过InvocationHandler拦截方法调用。它是Java标准库的一部分,无需额外依赖,但要求目标对象实现接口。
CGLIB代理通过字节码生成目标类的子类实现代理,不要求接口但无法代理final类/方法。Spring默认在Boot
2.x+中使用CGLIB作为AOP代理。
性能方面,缓存反射对象、使用setAccessible(true)、考虑MethodHandle替代是关键优化手段。在性能极敏感的场景,编译时增强方案(如APT、字节码插桩)是更好的选择。
Spring
AOP的代理选择遵循明确的规则:有接口默认JDK代理,无接口或配置proxyTargetClass=true时使用CGLIB。理解这一机制有助于排查自注入、类型转换等常见问题。