CGLIB實現動態代理


介紹

cglib是一個強大的,受歡迎的,高性能的代碼生成類庫,它的底層就是asm(字節碼框架),可以用來動態修改class和創建class,Spring AOP實現動態代理的一種方式就是cglib,hibernate使用cglib對持久化對象創建代理。

實現動態代理

引入maven依賴

<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>3.3.0</version>
</dependency>

實現

public class Client {
  public static void main(String[] args) {
//設置cglib生成的源碼目錄
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\");
    Enhancer enhancer = new Enhancer();
//設置父類
    enhancer.setSuperclass(Singer.class);
//設置方法攔截處理器
    enhancer.setCallback(new SingerMethodInterceptor());
//創建代理對象
    Singable singable = (Singable) enhancer.create();
    singable.sing();
  }

  public static class SingerMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("cglib before");
      Object result = methodProxy.invokeSuper(obj, objects);
      System.out.println("cglib after");
      return result;
    }
  }
}

輸出結果為

cglib before
I am singing...
cglib after

可以看到確實實現了動態代理的功能,JDK動態代理創建的類默認繼承Proxy類,所以不能繼承其他類,cglib沒有這個限制,可以通過繼承類的方式代理類。
方法攔截器的參數依次為:

  1. obj,表示創建的代理對象
  2. method,代理的方法,如sing
  3. objects,方法參數
  4. methodProxy,封裝了代理方法,代理對象和原對象

創建不可變對象

public class Client {
  public static void main(String[] args) {
    User user = new User("lisi");
//根據user對象創建一個不可變對象
    User immutableUser = (User) ImmutableBean.create(user);
    System.out.println(immutableUser);
//當我們修改了原對象,不可變對象也被修改了
    user.setName("lisi3");
    System.out.println(immutableUser);
    immutableUser.setName("lisi2");
    System.out.println(immutableUser);
  }

  @Getter
  @Setter
  @AllArgsConstructor
  @NoArgsConstructor
  @ToString
  public static class User {

    private String name;
  }
}

當我們修改不可變對象時,會拋出異常

Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
	at com.imooc.sourcecode.java.dynamicproxy.cglib.test2.Client$User$$ImmutableBeanByCGLIB$$98871c2c.setName(<generated>)
	at com.imooc.sourcecode.java.dynamicproxy.cglib.test2.Client.main(Client.java:17)

但是如果我們修改原對象,那么不可變對象也會相應的被修改。這是因為不可變對象是通過繼承原類,然后重寫Getter,setter方法實現的,Getter直接調用原對象的Getter,setter直接拋出異常。

對象生成器

public class Client {
  public static void main(String[] args) throws Exception {
    BeanGenerator beanGenerator = new BeanGenerator();
    beanGenerator.addProperty("name", String.class);
    Object bean = beanGenerator.create();
    Method setNameMethod = bean.getClass().getMethod("setName", String.class);
    setNameMethod.invoke(bean,"lisi");
    Method getNameMethod = bean.getClass().getMethod("getName");
    System.out.println(getNameMethod.invoke(bean));
  }
}

運行時創建一個對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM