按照代理的建立時期,代理類能夠分爲兩種。
靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態建立而成。java
動態代理實現有三種方式,jdk動態代理(基於接口),cglib動態代理(基於繼承),javassist(hibernate中使用這種方式)實現動態代理。程序員
JDK實現動態代理須要實現類經過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢?
這就須要CGLib了。框架
Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類,使用CGLIB即便代理類沒有實現任何接口也能夠實現動態代理功能。maven
CGLib原理是經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。ide
CGLib建立的動態代理對象性能比JDK建立的動態代理對象的性能高很多,可是CGLib在建立代理對象時所花費的時間卻比JDK多得多,因此對於單例的對象,由於無需頻繁建立對象,用CGLib合適,反之,使用JDK方式要更爲合適一些。同時,因爲CGLib因爲是採用動態建立子類的方法,對於final方法,沒法進行代理。工具
下面演示一個動態代理的實例。性能
cglib 是基於asm 字節修改技術。導入 cglib 會間接導入 asm, ant, ant-launcher 三個jar 包。測試
<!-- cglib 動態代理依賴 begin --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version></dependency> <!-- cglib 動態代理依賴 stop -->
CGLIB的核心類:優化
public class HelloService { public HelloService() { System.out.println("HelloService構造"); } public void sayHello() { System.out.println("HelloService:sayHello"); }
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它常常被基於代理的AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;編碼
方法攔截器 實現 MethodInterceptor 接口:
public class HelloServiceInterceptor implements MethodInterceptor{ /** * sub:cglib生成的代理對象 * method:被代理對象方法 * objects:方法入參 * methodProxy: 代理方法 */ @Override public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("======插入前置通知======"); Object object = methodProxy.invokeSuper(sub, objects); System.out.println("======插入後置通知======"); return object; }
測試類,生成CGLIB代理對象調用目標方法:
public class CglibTest { public static void main(String[] args) { // 經過CGLIB動態代理獲取代理對象的過程 Enhancer enhancer = new Enhancer(); // 設置enhancer對象的父類 enhancer.setSuperclass(HelloService.class); // 設置enhancer的回調對象 enhancer.setCallback(new HelloServiceInterceptor()); // 建立代理對象 HelloService proxy= (HelloService)enhancer.create(); // 經過代理對象調用目標方法 proxy.sayHello(); } }