java中的東岱代理機制是動態生成代理接口的實例類,在代理類的invoke方法中可以在實際方法執行時做用戶自定義的一些操作,spring中的aop就是用這個原理來執行的。
先看看普通的動態代理是怎么使用的。
1、先聲明一個接口
package testmybatis; public interface IFruit { void eat(); void shape(); }
2、生成實現類
package testmybatis; public class Apple implements IFruit { public void eat() { // TODO Auto-generated method stub System.out.println("吃了一個蘋果"); } public void shape() { // TODO Auto-generated method stub } }
3、編寫動態代理類
package testmybatis; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import javax.swing.plaf.basic.BasicComboPopup.InvocationKeyHandler; public class MyProxy implements InvocationHandler { Object target; public MyProxy(Object target){ this.target=target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 此處為方法實際執行的地方,當然你也可以根本就不執行此方法,mybatis就是根本不管這里的方法,他需要的只是方法名,用方法名來找到對應的sql語句,參數,返回值的信息 Object result=method.invoke(target, args); return result; } }
4、測試動態代理
public void testApp() { // MyProxy proxy=new MyProxy(new Apple()); IFruit app=(IFruit)Proxy.newProxyInstance(IFruit.class.getClassLoader(), new Class[] {IFruit.class}, proxy); app.eat(); }
這樣app就是通過動態代理生成的IFruit的實現類了,這個類就是經過代理有的apple。現在實現類執行方法的時候其實就是在調用
代理的Object result=method.invoke(target, args)這段代碼,其中target是我們自己實現的一個實現類,如果要在這里確實執行方法,那么就必須傳入一個實現類。但是mybatis根本就不需要執行接口的方法,所以這里可以不用傳入類的實例。
接下來看看mybatis的實現方式吧,我們只看他核心的生成部分代碼
mybatis中的org.apache.ibatis.binding.MapperRegistry類里有一個getMapper方法,代碼如下:
@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) throw new BindingException("Type " + type + " is not known to the MapperRegistry."); try {
//返回實現類 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
這里從MapperProxyFactory中得到了代理后類。點擊mapperProxyFactory.newInstance(sqlSession),看他是如何執行的。
@SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) {
//用動態代理生成實現類,mapperProxy就是代理類的實例
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) {
//實例化proxy類 final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
先調了 public T newInstance(SqlSession sqlSession) 這個方法,這個方面又調用了上面的 protected T newInstance(MapperProxy<T> mapperProxy),這里就是真正生實現類的地方了。
(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy)
這句話生成了實現類,其中 mapperInterface是mapper接口,mapperproxy是動態代理類,我們所有的sql查詢都是通過他來完成。我們看看他的代碼。
package org.apache.ibatis.binding; import java.io.Serializable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; import org.apache.ibatis.reflection.ExceptionUtil; import org.apache.ibatis.session.SqlSession; /** * @author Clinton Begin * @author Eduardo Macarron */ public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } final MapperMethod mapperMethod = cachedMapperMethod(method);
//執行真正的查詢 return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { MapperMethod mapperMethod = methodCache.get(method); if (mapperMethod == null) { mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod); } return mapperMethod; } }
代碼不多也不復雜,看invoke方法。
//如果傳進來的 object對象就執行相應的發布方法
if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }
//真正執行的sql查詢的地方,sqlsession封裝了數據庫已經需要執行的語句等信息,args包含了執行所需要的參數 final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args);
以上就是mybatis如果通過接口實現查詢的一個過程,當然,動態代理生成實現類並不是在每次請求時,而是在一開始初始化時就已經生成並緩存了起來,核心的流程其實就是通過動態代理來完成查詢動作的。
當然里面還有很多配置文件解析xml解析緩存等工作需要做,不過了解了整個流程以后就可以慢慢一步一步的去看他是怎么完成的了