動態代理概述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; }