一、概述
Java代理就是客户类不再直接和委托类打交道,二十通过一个中间层来访问,这个中间层就是代理,代理可以隐藏委托类的实现,可以实现客户和委托类之间的解耦,在不修改委托类代码的情况下能做一些额外的处理。
代理主要分为静态代理、JDK动态代理和CGLIB动态代理。
二、Java静态代理
静态代理的关系在编译期间就已经确定了。首先需要定义接口和其实现类,然后定义代理对象,代理对象中注入接口的实例,然后通过代理对象去调用真正的实现类。它可以实现在不修改委托类的强开下做一些额外的处理;试用于代理类较少的情况。如果在委托类很多的情况下,那就需要使用动态代理了。
静态代理三、JDK动态代理
在JVM中,类加载阶段主要有三个阶段:
(1)通过一个类的全限定名来获取这个类的二进制字节流,包括从ZIP包,网络,运行时计算生成,其他文件,数据库获取。
(2)将字节流所代表的的静态存储结构转换为方法区的运行时结构。
(3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区访问这个类的入口。
而其中第一阶段的运行时计算生成的类就是动态代理技术,在Proxy类中,就是用了ProxyGenerator.generateProxyClass来为特定接口生成*$Proxy代理类的二进制字节流。
在JDK动态代理中主要涉及到java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。需要实现一个InvocationHandler接口的中间类,这个接口只有一个invoke方法,委托类的所有方法的调用都会变成对invoke方法的调用,这样就可以在invoke方法中添加统一的处理逻辑。中间类有一个委托类对象的引用,把外部对invoke的调用最终对转换为对委托类的调用。
实际上中间类的委托类构成了静态代理关系,然后代理类个中间类也构成了静态代理关系,也就是说动态代理时由两组静态代理关系组成。
JDK代理主要实现JDK代理的最大的特点就是动态生成的代理类和委托类实现同一个接口。JDK动态代理其实就是内部通过反射机制实现,就是已知一个对象,在运行时动态调用它的方法,并且调用的时候还可以加一些自己的逻辑。
四、CGLIB动态代理
JDK动态代理依赖接口实现,当只有类没有接口的时候,就需要用到CGLIB代理,CGLIB代理时第三方实现的。
CGLIB代理时针对类来实现代理的,原理是对指定的委托类生成一个子类并重写其中业务方法实现代理,代理类对象是由Enhancer类创建的。
CGLIB创建动态代理类的模式是:
(1)查找目标类的所有非final的public方法(final方法不能被重写)。
(2)将这些方法定义转成字节码。
(3)将组成的字节码转换成相应的代理的Class对象然后通过反射获得代理类的实例对象。
(4)实现MethodInterceptor接口,用来处理对代理类上所有方法的请求。
CGLIB动态代理的实现对于需要代理的类,只是动态生成了一个子类以覆盖非final的方法,同时绑定回调自定义的拦截器。这种实现比JDK动态代理快。
五、总结
1、静态代理需要委托类和代理类来自同一个接口,然后地里种调用真正的实现类,静态代理的关系在编译期间就确定了。而动态代理是在运行期确定的。静态代理实现简单,适合代理类较少且确定的情况,动态代理具有更大的灵活性。
2、JDK动态代理的代理类,是在程序调用的时候才被JVM创建,JVM根据传进来的对象和方法名,动态创建一个代理类的class文件并执行,然后通过该代理类对象进行方法调用。
3、静态代理和JDK动态代理都是基于接口实现的,对于没有提供接口只有实现类的类,只能用CGLIB动态代理。
4、JDK代理和CGLIB代理的区别
JDK动态代理基于Java的反射机制实现,必须要要实现接口的实现类才能使用这种方法生成代理对象。
CGLIB动态代理基于ASM通过生成业务类的子类来实现。
JDK动态代理的优势是最小依赖关系,减少以来以为着简化开发和维护,并且有JDK自身支持,可以平滑的进行JDK升级,代码实现简单。
基于CGLIB的又是是无须实现接口,达到代理类无侵入。
网友评论