Skip to content
清晨的一缕阳光
返回

反射与动态代理详解

反射与动态代理详解

反射是 Java 框架的基石,理解反射和动态代理对掌握 Spring 等框架至关重要。

一、反射机制

1.1 什么是反射

反射 = 运行时获取类信息 + 动态操作对象

运行时获取:
- 类的属性、方法、构造函数
- 注解、泛型信息

运行时操作:
- 创建对象
- 调用方法
- 访问属性

1.2 获取 Class 对象

// 方式 1:Class.forName()
Class<?> clazz = Class.forName("com.example.User");

// 方式 2:类名.class
Class<User> clazz = User.class;

// 方式 3:对象.getClass()
User user = new User();
Class<?> clazz = user.getClass();

// 方式 4:类加载器
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = loader.loadClass("com.example.User");

二、反射核心 API

2.1 创建对象

Class<?> clazz = Class.forName("com.example.User");

// 方式 1:无参构造
User user1 = (User) clazz.newInstance(); // 已废弃

// 方式 2:指定构造器
Constructor<User> constructor = clazz.getDeclaredConstructor();
User user2 = constructor.newInstance();

// 方式 3:有参构造
Constructor<User> constructor = clazz.getDeclaredConstructor(String.class, int.class);
User user3 = constructor.newInstance("Alice", 20);

2.2 访问属性

Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();

// 获取公共属性
Field nameField = clazz.getField("name");

// 获取任意属性(包括私有)
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true); // 突破访问限制

// 设置/获取值
ageField.set(user, 20);
int age = (int) ageField.get(user);

// 获取所有属性
Field[] fields = clazz.getDeclaredFields();

2.3 调用方法

Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();

// 获取公共方法
Method getNameMethod = clazz.getMethod("getName");

// 获取任意方法(包括私有)
Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
setNameMethod.setAccessible(true);

// 调用方法
setNameMethod.invoke(user, "Alice");
String name = (String) getNameMethod.invoke(user);

// 调用静态方法
Method staticMethod = clazz.getDeclaredMethod("staticMethod");
staticMethod.invoke(null); // 静态方法传入 null

三、反射应用场景

3.1 工厂模式

public class BeanFactory {
    public static <T> T createBean(Class<T> clazz) {
        try {
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

// 使用
UserService service = BeanFactory.createBean(UserService.class);

3.2 依赖注入

public @interface Autowired {}

public class SpringContainer {
    private Map<String, Object> beans = new HashMap<>();
    
    public void register(Class<?> clazz) {
        try {
            Object bean = clazz.getDeclaredConstructor().newInstance();
            
            // 注入依赖
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    Object dependency = beans.get(field.getType().getName());
                    field.set(bean, dependency);
                }
            }
            
            beans.put(clazz.getName(), bean);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3.3 动态配置

public class ConfigLoader {
    public static <T> T loadConfig(Class<T> clazz, Properties props) {
        try {
            T config = clazz.getDeclaredConstructor().newInstance();
            
            for (Field field : clazz.getDeclaredFields()) {
                String key = field.getName();
                if (props.containsKey(key)) {
                    field.setAccessible(true);
                    String value = props.getProperty(key);
                    
                    // 类型转换
                    if (field.getType() == int.class) {
                        field.set(config, Integer.parseInt(value));
                    } else if (field.getType() == boolean.class) {
                        field.set(config, Boolean.parseBoolean(value));
                    } else {
                        field.set(config, value);
                    }
                }
            }
            
            return config;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

四、动态代理

4.1 什么是动态代理

动态代理 = 运行时创建代理类

优势:
- 无需手动编写代理类
- 统一处理横切逻辑
- AOP 实现基础

4.2 JDK 动态代理

// 接口
interface UserService {
    void addUser(String name);
}

// 目标对象
class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
}

// 创建代理
UserService target = new UserServiceImpl();

UserService proxy = (UserService) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    (proxyObj, method, args) -> {
        // 前置处理
        System.out.println("Before: " + method.getName());
        
        // 调用目标方法
        Object result = method.invoke(target, args);
        
        // 后置处理
        System.out.println("After: " + method.getName());
        
        return result;
    }
);

// 使用代理
proxy.addUser("Alice");

4.3 代理工厂

public class ProxyFactory {
    
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target, InvocationHandler handler) {
        return (T) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            handler
        );
    }
    
    // 事务代理
    public static <T> T createTransactionProxy(T target, DataSource dataSource) {
        return createProxy(target, (proxy, method, args) -> {
            Connection conn = dataSource.getConnection();
            try {
                conn.setAutoCommit(false);
                Object result = method.invoke(target, args);
                conn.commit();
                return result;
            } catch (Exception e) {
                conn.rollback();
                throw e;
            } finally {
                conn.close();
            }
        });
    }
    
    // 日志代理
    public static <T> T createLoggingProxy(T target) {
        return createProxy(target, (proxy, method, args) -> {
            System.out.println("Calling: " + method.getName());
            long start = System.currentTimeMillis();
            Object result = method.invoke(target, args);
            long cost = System.currentTimeMillis() - start;
            System.out.println("Cost: " + cost + "ms");
            return result;
        });
    }
}

五、CGLIB 动态代理

5.1 为什么需要 CGLIB

JDK 动态代理限制:
- 只能代理接口
- 不能代理类

CGLIB 优势:
- 可以代理类
- 通过继承实现

5.2 CGLIB 使用

// 添加依赖
// <dependency>
//     <groupId>cglib</groupId>
//     <artifactId>cglib</artifactId>
//     <version>3.3.0</version>
// </dependency>

// 目标类(无接口)
class UserService {
    public void addUser(String name) {
        System.out.println("Adding user: " + name);
    }
}

// 创建代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
    System.out.println("Before: " + method.getName());
    Object result = proxy.invokeSuper(obj, args);
    System.out.println("After: " + method.getName());
    return result;
});

UserService proxy = (UserService) enhancer.create();
proxy.addUser("Alice");

5.3 JDK vs CGLIB

特性JDK 动态代理CGLIB
实现方式接口继承
代理对象接口实现类任意类
性能稍低
依赖JDK 自带需要第三方库
Spring 选择有接口用 JDK无接口用 CGLIB

六、Spring AOP 原理

6.1 AOP 核心概念

Aspect(切面) = 横切关注点的模块化
Pointcut(切入点) = 匹配连接点的谓词
Advice(通知) = 切面在特定执行的动作
Joinpoint(连接点) = 程序执行的点(方法调用)
Weaving(织入) = 将切面应用到目标对象

6.2 Spring AOP 实现

// 切面定义
@Aspect
@Component
public class LoggingAspect {
    
    // 切入点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 前置通知
    @Before("serviceMethods()")
    public void before(JoinPoint joinPoint) {
        System.out.println("Before: " + joinPoint.getSignature());
    }
    
    // 后置通知
    @After("serviceMethods()")
    public void after(JoinPoint joinPoint) {
        System.out.println("After: " + joinPoint.getSignature());
    }
    
    // 环绕通知
    @Around("serviceMethods()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long cost = System.currentTimeMillis() - start;
        System.out.println("Cost: " + cost + "ms");
        return result;
    }
}

6.3 Spring 代理选择

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    
    // 默认:有接口用 JDK,无接口用 CGLIB
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
    
    // 强制使用 CGLIB
    @Bean
    public ProxyFactoryBean proxyFactoryBean() {
        ProxyFactoryBean factory = new ProxyFactoryBean();
        factory.setProxyTargetClass(true); // 强制 CGLIB
        return factory;
    }
}

七、反射性能优化

7.1 缓存 Class 对象

// ❌ 每次都获取
Class<?> clazz = Class.forName("com.example.User");

// ✅ 缓存
private static final Class<?> USER_CLASS = User.class;

7.2 缓存 Method/Field

// ❌ 每次都查找
Method method = clazz.getMethod("getName");

// ✅ 缓存
private static final Method GET_NAME_METHOD;
static {
    try {
        GET_NAME_METHOD = User.class.getMethod("getName");
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
    }
}

7.3 关闭访问检查

// 访问私有方法/属性
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true); // 关闭检查,提升性能

// 使用后恢复
method.setAccessible(false);

八、总结

反射与代理核心要点:

主题核心 API应用场景
反射Class/Method/Field工厂、DI、配置
JDK 代理Proxy/InvocationHandler接口代理、AOP
CGLIBEnhancer/MethodInterceptor类代理、Spring AOP

反射是框架的基石,动态代理是 AOP 的基础,理解它们对掌握 Spring 至关重要。


分享这篇文章到:

上一篇文章
Java 字符串详解
下一篇文章
Java 泛型深度解析