一、关于反射
- 什么是反射:
反射机制是Java提供的一种基础功能,让程序能在运行时自省(introspect)的能力。通过反射我们能直接操作某个类或对象,甚至可以在运行时修改类定义。 - 反射的作用:
1、在运行时判断任意对象所属的类
2、在运行时任意构造一个类的对象
3、在运行时判断任意类所具有的成员变量和方法
4、在运行时调用任意对象的方法 - 应用场景:
反射技术常用在各类通用框架开发中。因为为了保证框架的通用性,需要根据配置文件加载不同的对象或类,并调用不同的方法,这个时候就会用到反射——运行时动态加载需要加载的对象。 - 特点:
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
二、动态代理
- 什么是动态代理:
动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制。这种代理机制可以让调用者与实现者之间解耦,如进行RPC调用、框架内部的寻址、序列化、反序列化以及面向切面编程(AOP)等等。 - 实现动态代理的方式:
JDK自身提供的动态代理(利用反射机制)或者ASM、CGLIB(基于ASM)、Javassist等。 - (动态)代理模式主要涉及三个要素:
其一:抽象类接口
其二:被代理类(具体实现抽象接口的类)
其三:动态代理类:实际调用被代理类的方法和属性的类
三、JDK Proxy与 cglib 动态代理
JDK Proxy:
- 举例:
常可采用的JDK提供的动态代理接口
InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。 - 局限性:
以接口为中心,相当于添加了一种对于被调用者没有太大意义的限制。我们实例化的是 Proxy 对象,而不是真正的被调用类型,这在实践中还是可能带来各种不便和能力退化。
如果被调用者没有实现接口,而我们还是希望利用动态代理机制,那么可以考虑其他方式。我们知道 Spring AOP 支持两种模式的动态代理,JDK Proxy 或者 cglib,如果我们选择 cglib 方式,你会发现对接口的依赖被克服了。
cglib 动态代理:
- cglib 动态代理采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果。在 Spring 编程中,框架通常会处理这种情况,当然我们也可以显式指定。
JDK Proxy 的优势:
- 最小化依赖关系,减少依赖意味着简化开发和维护,JDK 本身的支持,可能比 cglib 更加可靠。
- 平滑进行 JDK 版本升级,而字节码类库通常需要进行更新以保证在新版 Java 上能够使用。
- 代码实现简单。
基于类似 cglib 框架的优势:
- 有的时候调用目标可能不便实现额外接口,从某种角度看,限定调用者实现接口是有些侵入性的实践,类似 cglib 动态代理就没有这种限制。
- 只操作我们关心的类,而不必为其他相关类增加工作量。
- 高性能。