动态代理
动态代理
jdk动态代理:根据业务方法名,调用业生成的代理对象实例的同名方法。
cglib动态代理:通过继承业务类,并重写业务类的方法,生成的是业务类的子类。因为接口也能被继承,所以接口也可以被代理。
jdk低版本(jdk8以前)cglib创建代理对象性能高,但耗时久,故单例对象适合用cglib创建,否则适合jdk动态代理。jdk8及以后jdk动态代理性能已经高于cglib了。
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
- JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
- 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
为什么jdk动态代理需要实现接口
通过反编译,当用 Proxy.newInstance(classloader, interface, invocationHandler)来创建代理时,jdk动态代理最终生成的代理类$Proxy0已经继承了Proxy类($Proxy0 extends Proxy),java是单继承多实现的,所以只能通过接口实现($Proxy0 extends Proxy implements 你的Interface)来生成和原来一模一样效果的代理类。不管是jdk还是cglib,java是不知道用户想传什么类进来的,所以只能根据传进来的class反推原类的方法,为了能生成一个和原来接口一模一样的效果的代理类,就需要通过继承或实现,但已经继承了Proxy,那么就只剩下实现这一条路来建立联系了,所以需要实现接口接口来反推原来的方法。
为什么cglib不能代理final类?
由于cglib是基于继承的方式实现类的动态代理,因此无法实现对final方法的代理。