详解反射机制和动态代理原理
1. 反射是什么
反射:是基于反射分析类的信息,然后获取到类/成员变量/成员方法/成员方法的参数
2. 代码举例
普通创建对象
1 2 3
| User user = new User(); user.setUserName("李四"); user.setAge(20);
|
反射创建对象
1 2 3 4 5 6
| Class<?> clazz = Class.forName("com.oimc.aimin.test.entity.User"); Object obj = clazz.getDeclaredConstructor().newInstance();
Field field = clazz.getDeclaredField("userName"); field.setAccessible(true); field.set(obj, "李四");
|
普通创建对象是“编译期确定类”,反射是“运行期动态确定类”
- 普通创建对象:类在编译期已经写死
- 反射创建对象:类是字符串加载,运行期才知道是哪个类
最关键的区别:“能不能提前知道类是谁”
普通new:你必须提前知道类
- 编译器必须能找到
User.class
- 如果你删了
User,项目直接编译失败
反射:类是“运行时加载”的
1
| Class.forName("com.xxx.User");
|
- 编译期根本不知道
User 是否存在
- 只在程序运行时才去磁盘加载 class
- 你可以:
3. 真实框架场景–Spring 为什么用反射,而不用 new?
当你注册一个bean时,Spring加载这个bean对象的时候使用的反射机制,而不是直接new一个UserService
1 2
| @Service public class UserService {}
|
因为:
Spring容器启动时根本不知道你会写哪些类!
Spring 做的是:
- 扫描包路径 → 找到
UserService.class
- 通过反射创建对象
- 通过反射注入
@Autowired 的属性
- 放入 IOC 容器
如果不用反射:
4. 使用反射的场景
| 场景 |
是否必须反射 |
| 框架底层(Spring) |
✅ |
| IOC / DI 容器 |
✅ |
| ORM 映射 |
✅ |
| 动态代理 |
✅ |
| 插件化系统 |
✅ |
| 反序列化 |
✅ |
5. 反射的优缺点
优点
- 动态性:打破编译期限制,运行时动态操作类,适合框架开发(无需硬编码类信息)。
- 灵活性:可适配不同类的通用逻辑(如 ORM 框架的对象映射)。
- 扩展性:通过反射加载外部类(如插件),增强程序扩展性。
缺点
- 性能损耗:反射操作绕过编译期优化,比直接调用慢 10-100 倍(频繁调用需缓存 Class/Method 对象优化)。
- 破坏封装:setAccessible(true) 可访问私有成员,违反类的封装设计。
6. 动态代理
动态代理的实现
动态代理是在运行时通过反射机制生成代理对象,在不修改目标类源码的前提下,对方法进行增强。
1 2
| 业务类:只负责业务 代理类:统一负责事务 / 日志 / 权限
|
JDK 动态代理完整示例
在不修改 UserServiceImpl 源码的前提下,为 addUser() 方法自动添加“开启事务 + 提交事务”的增强逻辑。
1️⃣ 定义接口(必须有接口)
1 2 3
| public interface UserService { void addUser(); }
|
2️⃣ 真实实现类(被代理的目标对象)
1 2 3 4 5 6 7
| public class UserServiceImpl implements UserService {
@Override public void addUser() { System.out.println("执行业务:添加用户"); } }
|
3️⃣ 创建动态代理(核心)
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
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【开启事务】"); Object result = method.invoke(target, args); System.out.println("【提交事务】");
return result; } } );
proxy.addUser(); } }
|
4️⃣ 运行结果
有动态代理:
没有动态代理:
7. 动态代理 vs 反射 vs 普通 new
| 技术 |
作用 |
| new |
创建“真实对象” |
| 反射 |
运行时“操作对象” |
| 动态代理 |
运行时“生成增强对象” |
动态代理 = 反射的高级形态
END