之前我們在Spring AOP簡介里面寫了一個簡單的面向切面編程的小栗子,其實AOP的核心是其實現(xiàn)了兩種代理模式:JDK和CGLIB動態(tài)代理
在了解這兩種動態(tài)代理之前粟害,我們先了解下什么是代理:
代理和現(xiàn)實生活中的中介有很大的類似,你買房子、賣房子,可以自己去操作囤屹,但是需要了解和買賣房產無關的細節(jié),如契稅等逢渔,而找一個中介牺丙,則不用關心這些與買賣房產無直接關系的中間細節(jié),只關心業(yè)務本身复局。-----這是不是就是我們切面編程想要達到的效果?
那么代理又分兩種:靜態(tài)代理和動態(tài)代理
靜態(tài)代理:一個代理類只能對一個業(yè)務接口的實現(xiàn)類進行包裝粟判,屬于“硬編碼”亿昏,如果有多個業(yè)務接口的話就要定義很多實現(xiàn)類和代理類才行;而且因為代理類里面代理處置的事情經常是共同的档礁,這樣多個代理類就會有很多重復代碼
動態(tài)代理:它能代理所有實現(xiàn)類的方法調用:根據傳進來的業(yè)務實現(xiàn)類和方法名進行具體調用角钩,而不再是對一個具體的業(yè)務接口實現(xiàn)類進行包裝,這樣就大大增加了代理類的靈活性
好了呻澜,說了那么多代理的概念递礼,現(xiàn)在我們來說說Spring AOP里面這兩個代理類:
JdkDynamicAopProxy:實現(xiàn)了InvocationHandler接口,將被代理對象和攔截器作為參數傳入羹幸,然后生成代理脊髓,是在程序調用到代理類對象時才由JVM真正創(chuàng)建,我們稱之為JDK動態(tài)代理
綁定業(yè)務類并返回一個代理類:
實現(xiàn)invoke完成對業(yè)務方法的代理調用并實現(xiàn)代理類的功能:
CglibAopProxy:實現(xiàn)了Cglib的MethodInterceptor接口栅受,使用了CGLIB加強器來創(chuàng)建動態(tài)代理類
然后通過回調來使用業(yè)務類(父類)中的方法将硝,完成代理操作
在Spring AOP中,如果不是強制配置<aop:aspectj-autoproxy proxy-target-class="true"/>屏镊,則Spring回根據判斷targetClass(具體業(yè)務類)是否有實現(xiàn)接口來確定使用哪一種代理依疼,如果實現(xiàn)了接口則使用JDK動態(tài)代理,如果沒有實現(xiàn)接口則使用Cglib代理而芥,所以我們一般會配置為律罢、<aop:aspectj-autoproxy />,將選擇權交給Spring
PS:由于Cglib代理是利用ASM字節(jié)碼生成框架在內存中生成一個需要被代理類的子類完成代理棍丐,而JDK動態(tài)代理是利用反射原理完成動態(tài)代理误辑,所以Cglib創(chuàng)建的動態(tài)代理對象性能比JDk動態(tài)代理動態(tài)創(chuàng)建出來的代理對象新能要好的多沧踏,但是對象創(chuàng)建的速度比JDk動態(tài)代理要慢,所以稀余,當Spring使用的是單例情況下可以選用Cglib代理悦冀,反之使用JDK動態(tài)代理更加合適。(JDK7以后版本睛琳,代理對象性能差異已經不很明顯了盒蟆,反而CGLIB比較新的版本,動態(tài)代理對象的創(chuàng)建速度比JDK要快师骗,我是在CGLIB3.2.6和JDK8版本的基礎上測試的)
同時還有一個問題历等,被final修飾的類只能使用JDK動態(tài)代理,因為被final修飾的類不能被繼承辟癌,而Cglib則是利用的繼承原理實現(xiàn)代理的寒屯,否則會報如下異常
有需要資料的可以加群:1023705513