mybatis源碼分析(3)——SqlSessionManager類


從上圖可能看出,在 mybatis中,SqlSession的實現類有兩個,其中SqlSessionManager類不但實現了SqlSession接口,同時也實現了SqlSessionFactory接口。那么SqlSessionManager類究竟有何作用 由於源碼中缺少注釋,所以從mybatis目前的提供官方文檔來看,似乎該類已被棄用,其功能被DefaultSqlSession類和DefaultSqlSessionFactory類所代替。只是該類的部分代碼對我們理解mybatis的一些底層機制還具有一定的參考價值,例如:

SqlSessionManager的下面的構造方法,會產生一個SqlSession的一個代理對象:

 

private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
}

 

SqlSessionInterceptor類實現了InvocationHandler接口

privaprivate class SqlSessionInterceptor implements InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   
  {
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      if (sqlSession != null) {
        try {
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      } else {
        final SqlSession autoSqlSession = openSession();
        try {
          final Object result = method.invoke(autoSqlSession, args);
          autoSqlSession.commit();
          return result;
        } catch (Throwable t) {
          autoSqlSession.rollback();
          throw ExceptionUtil.unwrapThrowable(t);
        } finally {
          autoSqlSession.close();
        }
      }
    }
  }
private class SqlSessionInterceptor implements InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   
  {
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      if (sqlSession != null) {
        try {
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      } else {
        final SqlSession autoSqlSession = openSession();
        try {
          final Object result = method.invoke(autoSqlSession, args);
          autoSqlSession.commit();
          return result;
        } catch (Throwable t) {
          autoSqlSession.rollback();
          throw ExceptionUtil.unwrapThrowable(t);
        } finally {
          autoSqlSession.close();
        }
      }
    }
  }

下面對這一段使用JAVA動態代理技術產生SqlSession代理對象的代碼進行分析:

this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(

        SqlSessionFactory.class.getClassLoader(),

        new Class[]{SqlSession.class},

        new SqlSessionInterceptor())  這句是關鍵,JDKProxy類的newProxyInstance方法的方法原型如下:

public static Object newProxyInstance(ClassLoader loader,

  Class<?>[] interfaces,

  InvocationHandler h)

throws IllegalArgumentException

在調這個方法中需要傳入三個參數:

Ø 一個interfaces的數組參數

Ø 一個InvocationHanler 接口的實例對象

Ø 一個類加載器,

則Proxy.newProxyInstance方法執行后會返回interfaces中任一接口的實例對象(假設該對象為proxyObject),那么當我們在調用這個對象proxyObject的相應方法時,就會進入到InvocationHandler 這個參數對象的invoke(Object proxy, Method method, Object[] args)方法中,或者換句話說,就會被h這個對象的invoke方法攔截對象proxyObject會作為

Invoke中的proxy參數,proxyObject調用的方法的方法對象會作為method參數,方法的參數會作為args參數,這樣在InvocationHandler 對象的invoke方法中,就會通過Method.invoke方法來執行具體的目標對象的相應方法,在mybatis的這個應用場景上,這個目標對象其實就是一個SqlSession的實例,通過SqlSessionManager類的成員變量sqlSessionFactory的openSession()獲得或者從當前線程中獲取。

 

以上的實現技術主要就是使用了java的動態代理技術,看到網上不少人在問這個InvocationHandler 接口中的invoke方法的第一個參數proxy究竟有何作用,這個proxy其實就是一個代理對象實例(通過Proxy.newProxyInstance方法產生),下面就舉例說明一下它的作用:

可參照 java.rmi.server.RemoteObjectInvocationHandler類中的相應方法invoke方法,一個用法就是判斷invokemethod參數,看是否有必要調用proxy對象的其他方法,另一個用處就是作為參數把該對象提供給遠程調用的方法使用。 


免責聲明!

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



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