动态代理的使用场景
- 保护目标对象
- 增强目标对象(例如 中介 黄牛 快递小哥,专人干专事)
静态代理和动态代理对比
- 静态代理:显示声明被代理对象
JDK动态代理
Java1.3以后,Java提供了动态代理技术,允许开发者在运行期间创建接口的代理实例。在Sun推出动态代理时,很难想象它有多大的实际用途,但后来发现它是实现AOP的绝好底层技术。
主要类包括Proxy和InvocationHandler
InvocationHandler
InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务代码编制在一起。
Proxy
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
CGLib动态代理
使用JDK创建代理有一个限制,只能为接口创建代理实例,可以从创建代理对象的参数看得很清楚。
CGLib作为一个替补者,填补了这项空缺。
CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
MethodInterceptor
1、通过实现MethodInterceptor接口,创建一个可以为任何类创建织入横切逻辑代理对象的代理创建器
2、核心方法interceptor(Object obj,Method method,Object[] args,MethodProxy proxy),拦截所有目标类方法的调用。
obj:目标类的实例
method:目标类方法的反射对象
args:方法的动态入参
proxy:代理类实例
注意点
CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final或private方法进行代理。final和private方法无法被子类重写。
动态代理需要改进的地方
- 目标类的所有方法都被添加了横切逻辑,而不是在业务中我们期望的某些特定的方法上进行织入逻辑。
- 通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结束前织入代码。
- 手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的创建代码,无法做到重用。
SpringAOP的主要功能
- SpringAOP通过PointCut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前,方法后,方法的两端、异常环绕等)
- Spring通过Advisor(切面)将Pointcut和Advice组装起来,有了Advisor的信息,Spring就可以利用JDK或CGLib动态代理技术采用统一的方式为目标Bean织入切面的代理对象。
JDK与CGLib性能对比
- 有研究表明CGLib所创建的动态代理对象的性能比JDK所创建的动态代理对象的心梗高不少(大概10倍)。
- CGLib在创建代理对象时所花费的时间比JDK动态代理多(大概8倍)
使用场景
对于Singleton的代理对象或者具有实例池的代理,因为无须频繁地创建代理对象,适合采用CGLib动态代理技术,反之适合采用JDK动态代理技术。