性能優於JDK代理,CGLib如何實現動態代理

按照代理的建立時期,代理類能夠分爲兩種。
靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態建立而成。java

動態代理三種方式

動態代理實現有三種方式,jdk動態代理(基於接口),cglib動態代理(基於繼承),javassist(hibernate中使用這種方式)實現動態代理。程序員

JDK實現動態代理須要實現類經過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢?
這就須要CGLib了。框架

cglib如何實現代理

Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類,使用CGLIB即便代理類沒有實現任何接口也能夠實現動態代理功能。maven

CGLib原理是經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。ide

CGLib建立的動態代理對象性能比JDK建立的動態代理對象的性能高很多,可是CGLib在建立代理對象時所花費的時間卻比JDK多得多,因此對於單例的對象,由於無需頻繁建立對象,用CGLib合適,反之,使用JDK方式要更爲合適一些。同時,因爲CGLib因爲是採用動態建立子類的方法,對於final方法,沒法進行代理。工具

cgLib動態代理實例

下面演示一個動態代理的實例。性能

導入maven 依賴

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的核心類:優化

  • net.sf.cglib.proxy.Enhancer – 主要的加強類
  • net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,須要用戶實現
  • net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,能夠方便的實現對源對象方法的調用,如使用:
  •  Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個參數是被代理對象,也不會出現死循環的問題。

實現一個業務類,注意,這個業務類並無實現任何接口:

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();
    }
}

Cglib 總結

  • CGlib能夠傳入接口也能夠傳入普通的類,接口使用實現的方式,普通類使用會使用繼承的方式生成代理類.
  • 因爲是繼承方式,若是是 static方法,private方法,final方法等描述的方法是不能被代理的
  • 作了方法訪問優化,使用創建方法索引的方式避免了傳統JDK動態代理須要經過Method方法反射調用.
  • 提供callback 和filter設計,能夠靈活地給不一樣的方法綁定不一樣的callback。編碼更方便靈活。
  • CGLIB會默認代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
相關文章
相關標籤/搜索