mybatis源碼學習: 動態代理的應用(慢慢改)

  動態代理概述java

   在學spring的時候知道使用動態代理實現aop,入門的列子:須要計算全部方法的調用時間。能夠每一個方法開始和結束都獲取當前時間咋辦呢。相似這樣:git

long current=system.currenttimemillis();
調用原來的方法
long last=system.currenttimemillis();

若是每一個方法都人工加入實在有點不爽,動態代理出場了。動態代理利用字節碼技在原來對應的類的子節碼進行重寫,添加對應的邏輯。github

主流的動態代理實現技術主流以下:JDK 和CGLIB,Javassist,ASM  參考這個spring

mybatis的應用sql

  咱們知道在mybatis中,咱們只要編寫mapper的接口和接口對應的mapper.xml ,利用下面方法就能夠獲取實例和調用方法。(代碼來自mybatis3自帶測試用例apache

BoundBlogMapper mapper = session.getMapper(BoundBlogMapper.class);

Blog b = mapper.selectBlogWithPostsUsingSubSelect(1);
assertEquals(1, b.getId());
session.close();

這裏面的mapper就是利用jdk中的動態代理方式獲取的接口BoundBlogMapper的代理類的對象。具體方法本身看。很容易跟蹤。jdk動態代理最重要的就是實現session

InvocationHandler接口的處理累。最重調用以下。invoke方法中mapperMethod.execute(sqlSession, args)最重要
 1 public class MapperProxy<T> implements InvocationHandler, Serializable {
 2 
 3   private static final long serialVersionUID = -6424540398559729838L;
 4   private final SqlSession sqlSession;
 5   private final Class<T> mapperInterface;
 6   private final Map<Method, MapperMethod> methodCache;
 7 
 8   public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
 9     this.sqlSession = sqlSession;
10     this.mapperInterface = mapperInterface;
11     this.methodCache = methodCache;
12   }
13 
14   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
15     if (Object.class.equals(method.getDeclaringClass())) {
16       try {
17         return method.invoke(this, args);
18       } catch (Throwable t) {
19         throw ExceptionUtil.unwrapThrowable(t);
20       }
21     }
22     final MapperMethod mapperMethod = cachedMapperMethod(method);
23     return mapperMethod.execute(sqlSession, args);
24   }
25 
26   private MapperMethod cachedMapperMethod(Method method) {
27     MapperMethod mapperMethod = methodCache.get(method);
28     if (mapperMethod == null) {
29       mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
30       methodCache.put(method, mapperMethod);
31     }
32     return mapperMethod;
33   }
34 
35 }

根據幾種操做類型作不一樣處理mybatis

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    if (SqlCommandType.INSERT == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
    } else if (SqlCommandType.SELECT == command.getType()) {
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
    } else if (SqlCommandType.FLUSH == command.getType()) {
        result = sqlSession.flushStatements();
    } else {
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
相關文章
相關標籤/搜索