1. 程式人生 > >關於JDK動態代理和cglib動態代理

關於JDK動態代理和cglib動態代理

在spring AOP中,由於通知類中抽取了原始物件中的公共方法,使得原始物件的方法變得不能進行完整的操作。但是我們還是想通過某個方式實現原始物件完成完整操作,我們可以通過為原始物件建立代理物件的方式達到目的,有兩種方式:JDK動態代理和cglib動態代理。

一、JDK動態代理

  1、概述:針對記憶體中的Class物件,使用類載入器,動態為目標物件的實現介面建立代理物件。也就是說JDK代理是對物件做代理。

  2、具體實現(如下程式碼):

     建立一個介面及實現類     

     public interface UserDao {
      public void add();

     }

     public class UserDaoImp implements UserDao {

      @Override
      public void add() {
        System.out.println("新增使用者操作");

       }

     }

    建立實現JDK動態代理的工具類

    public class JdkProxy implements InvocationHandler {

      private UserDao userDao;

      // 定義一個方法用於建立JDK代理物件
      public UserDao createProxyObject(UserDao userDao) {
        // 被代理物件作為引數傳入進來
        this.userDao = userDao;
        // 獲取類載入器:對誰代理,使用誰的類載入器
        ClassLoader classLoader = userDao.getClass().getClassLoader();
        // 獲取被代理物件的所有實現介面
        Class<?>[] interfaces = userDao.getClass().getInterfaces();

        // 建立Handler物件,用於增強攔截,為了方便呼叫使用實現InvocationHandler介面的方式  

        InvocationHandler h = this;

        Object obj = Proxy.newProxyInstance(classLoader, interfaces, h);
          return (UserDao) obj;

    }

      @Override
      public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
        System.out.println("連線資料庫");// 增強操作
        // 對原始操作進行呼叫(使用反射)
        method.invoke(userDao, args);
        System.out.println("關閉資料庫");
        return null;
       }

      public static void main(String[] args) {
        // 1、建立一個物件
        UserDao dao = new UserDaoImp();
        // 2、為原始物件建立代理物件
        UserDao daoProxy = new JdkProxy().createProxyObject(dao);
        // 3、使用代理物件執行操作
        daoProxy.add();

      }
    }

二、cglib動態代理

  1、概述:非介面實現的物件,對於不使用介面的業務類,無法使用JDK動態代理。cglib採用底層位元組碼急速,可以為一個類建立子類,也就是cglib是解決無介面代理問題,

  是對類做代理。

       2、具體實現(如下程式碼)

  建立Person類及生成代理的方法

  public class Person {

    public void action() {
    System.out.println("Java程式設計師");
    }
  }

  public Person createProxyObject(Class clazz) {
    // cglib中的核心物件是Enhance,用來在記憶體中建立一段動態的類的位元組碼
    Enhancer enhancer = new Enhancer();//此時沒有做繼承
    // 為其指定父類,除了完成繼承關係外,還將父類所有的方法反射過來,並在自己的類中建立這些方法
    enhancer.setSuperclass(clazz);
    // 進行功能的增強
    // 設定方法的呼叫攔截
    Callback callback = new MethodInterceptor() {
      // proxy:代理物件
      // method:被攔截的方法物件
      // args:呼叫函式
      // methodProxy:使用代理機制建立被代理物件的方法
      @Override
      public Object intercept(Object proxy, Method method, Object[] args,
        MethodProxy methodProxy) throws Throwable {
        // 做增強
        System.out.println("Java後端程式設計師還會烤肉");
        // 呼叫原始的操作
        Object ret = methodProxy.invokeSuper(proxy, args);
        return ret;
      }
    };
  // 設定具體的回撥操作
  enhancer.setCallback(callback);
  // 建立記憶體中全新類的物件
  Object proxyObj = enhancer.create();
  return (Person) proxyObj;
  }

  3、小結:cglib動態代理機制其實是利用繼承的思想來實現,在程式碼中可以看出,代理機制建立代理物件,把被代理的物件當做父類,把代理的物件

當做子類,走父類執行,走子類的實現,這體現了繼承與多型的思想。

三、總結

  cglib可以對任意的類進行代理,JDKdial只能對介面實現的類進行代理。