动态代理和反射
动态代理和反射
由于这两个东西很重要经常用,所以我专门用一个文章来讲解,忘了就看着一个就够了
反射
反射机制就是在 运行的时候 获取类的结构信息,比如方法,字段,构造函数并操作对象的一种机制。
反射操作相对于静态调用有比较高的性能开销,因为他涉及到动态解析和方法调用。所以在性能敏感的场景中,尽量避免使用反射。可以通过 缓存反射结果 避免反射性能问题。
反射主要有个Class类,通过Class类的实例可以获取类的各种信息。
反射的主要主要功能:
- 创建对象:通过
Class.newInstance或者Constructor.newInstance()创建对象实例 - 访问字段:通过Field类访问和修改对象的字段。
- 调用方法:使用Method类调用对象的方法
- 获取类对象:获取类的名称、父类、接口等信息。
类的元数据存在方法区 / 元空间,Class 实例存在堆中,反射通过堆中的 Class 实例,访问方法区的元数据,进而操作对象。
动态代理
首先了解静态代理
一个租房子问题,中介就是这个原理。
缺点代理需要手动创建,简单来说就是房主和中介都要实现租房接口,这个租房接口规定了租房的规范,然后消费者只用调用中介的方法就能实现中介的很多方法并且最终实际租房的时候还是走的房东的租房方法,只是多加了很多中介的额外方法。
但是每次想要租房都得自己手动new一个中介出来。
动态代理
动态代理就是在静态代理的基础上利用反射实现动态代理.
java的动态代理分为基于jdk和cglib的,这里先说jdk的。
这里举个例子就是给用户服务添加服务日志的代理效果的动态代理。
1、定义目标接口,共同契约
1 | public interface UserService { |
2、实现目标类,被代理类,用于实现核心业务的
1 | public class UserServiceImpl implements UserService { |
3、实现InvocationHandler 这个是用来当拦截器 + 增强逻辑的
这里的作用就是把上面的核心业务包装一下,然后用InvocationHandler拦截器的作用,动态生成被代理对象本身,然后在方法前或者后进行增强。
1 | public class LogInvocationHandler implements InvocationHandler { |
4、创建代理工厂,简化代理对象生成。
这里就是编写一个工具类,动态生成上面的代理对象。
1 | public class ProxyFactory { |
这个工具类利用了Proxy类,的newInstance方法来生成代理对象,只用传入被代理对象的类加载器,被代理对象的接口,然后new拦截器,就能生成代理对象。
5、调用代理对象测试
首先创建目标对象,然后通过代理工厂生成代理对象,然后调用代理对象的方法就好了。
1 | public class JdkProxyTest { |
总结
| 组件 | 代码中的实现 | 核心作用 |
|---|---|---|
| 目标接口 | UserService |
定义方法契约,让代理类和目标类方法一致 |
| 目标类 | UserServiceImpl |
实现核心业务逻辑(被代理的对象) |
| InvocationHandler | LogInvocationHandler |
拦截方法调用,植入增强逻辑(日志、耗时) |
| Proxy 类 | Proxy.newProxyInstance() |
运行时动态生成代理类字节码并创建代理对象 |
| 代理工厂 | ProxyFactory |
封装代理对象生成逻辑,简化调用 |
| 对比维度 | 静态代理 | 动态代理 |
|---|---|---|
| 代理类生成时机 | 编译期手动编写(写死) | 运行时动态生成(自动) |
| 代码冗余度 | 一个目标类对应一个代理类,冗余高 | 一个处理器适配所有目标类,无冗余 |
| 灵活性 | 新增方法 / 目标类需修改代理类 | 新增方法 / 目标类无需修改处理器 |
| 依赖 | 需共同接口(和你说的一致) | JDK 需接口,CGLIB 无需接口 |
总结
jdk动态代理流程就是首先规定一个共同的接口,然后实现一个实现类实现接口写好核心业务,然后写自定义的MyInvocationHandler代理类实现InvocationHandler接口,然后在里面通过invoke方法然后在里面调用核心业务并且在核心业务前或后写增强代码,然后在写个代理生成工厂,用于动态生成刚刚的动态代理,然后这个代理工厂就用Proxy的newInstance方法生成代理类,然后传入代理类的类加载器和实现的接口还有拦截器就是刚刚的InvocationHandler就可以动态生成代理类了。然后使用的时候就新建目标对象,然后用代理工厂创建目标对象的代理对象,然后调用的时候用代理对象的方法就能实现增强方法了。
上面是jdk的动态代理,但是框架中常用的是cglib的动态代理
cglib是继承目标类而不是实现共同接口的
CGLIB 通过字节码技术,在运行时动态生成目标类的子类(subclass),并重写其中的非 final 方法,在方法调用前后插入自定义逻辑(如日志、事务等)。
也就是说:
- 不需要目标类实现任何接口;
- 代理对象是目标类的一个“增强子类”;
- 所有对代理对象的方法调用,都会进入你定义的 MethodInterceptor(拦截器)。




