代理模式
用途:控制对象的访问,或者增强对象功能
简单来说就是代理对象通过组合的方式获得被代理对象,且实现相同接口。在执行接口方法时,增加一些操作,并调用被代理对象的方法。
代理模式分为静态代理和动态代理。静态代理是程序员手动编写代理类,动态代理则是在程序运行期间动态生成代理类。由于静态代理违反了开闭原则,所以需要引入动态代理。
动态代理
动态代理有两种实现方式,一种是JDK方式,一种是CGLIB方式。
JDK方式
核心是java.lang.reflect中的Proxy类,和InvocationHandler接口。
一般使用流程是程序员通过注解标记需要被代理的类,之后框架在处理注解时通过Proxy类中的newProxyInstance静态方法生成代理类的对象(在内存中先生成字节码文件,再生成对象)。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
该方法有三个参数:
loader是被代理类的类加载器,用来确认当前的代理缓存上下文。(如果已经有代理类,不会重新生成)
interfaces是被代理类实现的接口。
h 就是实现了InvocationHandler的对象,其通过重新InvocationHandler对象的Invoke方法表明特定的增强操作(如事务)。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
生成的代理对象会替代被代理对象来执行对应的方法。
示例 可参考SrpingAop中实现InvocationHandler的对象org.springframework.aop.framework.JdkDynamicAopProxy.class
CGLIB方式
CGLIB主要解决JDK动态代理只能对接口实现类进行代理的问题。主要用字节码动态编辑的方式生成被代理类的子类对象作为代理类。
CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB缺点:对于final方法,无法进行代理。
网友评论