mybatis源码阅读(四):mapper(dao)实例化
生活随笔
收集整理的這篇文章主要介紹了
mybatis源码阅读(四):mapper(dao)实例化
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載自? ?mybatis源碼閱讀(四):mapper(dao)實例化
在開始分析之前,先來了解一下這個模塊中的核心組件之間的關系,如圖:
1.MapperRegistry&MapperProxyFactory
MapperRegistry是Mapper接口及其對應的代理對象工程的注冊中心,Configuration是Mybatis全局性的配置對象,在初始化的過程中,所有配置信息會被解析成相應的對象并記錄到Configuration對象中,這在之前也詳細介紹了。Configuration.mapperRegistry字段記錄當前使用的MapperRegistry對象,
public class MapperRegistry {// 全局唯一的配置對象,其中包含了所有的配置信息private final Configuration config;// 記錄Mapper接口與對應MapperProxyFactory之間的關系private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>(); }private void bindMapperForNamespace() {String namespace = builderAssistant.getCurrentNamespace();if (namespace != null) {Class<?> boundType = null;try {boundType = Resources.classForName(namespace);} catch (ClassNotFoundException e) {//ignore, bound type is not required}if (boundType != null) {if (!configuration.hasMapper(boundType)) {// Spring may not know the real resource name so we set a flag// to prevent loading again this resource from the mapper interface// look at MapperAnnotationBuilder#loadXmlResourceconfiguration.addLoadedResource("namespace:" + namespace);configuration.addMapper(boundType);}}} } public <T> void addMapper(Class<T> type) {mapperRegistry.addMapper(type); } public <T> void addMapper(Class<T> type) {if (type.isInterface()) {//是否為接口if (hasMapper(type)) {//是否已經加載過throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<T>(type));// 注解處理MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}} }在需要執行SQL語句時,會先獲取mapper借口的代理對象,例如:
@Test public void findUserById() {SqlSession sqlSession = getSessionFactory().openSession();UserDao userMapper = sqlSession.getMapper(UserDao.class);User user = userMapper.findUserById(1);Assert.assertNotNull("沒找到數據", user); }DefaultSqlSession類中方法如下,實際上是通過JDK動態代理生成的代理對象
public <T> T getMapper(Class<T> type) {return this.configuration.getMapper(type, this); }Configuration類方法如下:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession); }MapperRegistry類中方法如下:
@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) {//查找指定type對象的MapperProxyFactory對象final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) {//如果為空拋出異常throw new BindingException("Type " + type + " is not known to the MapperRegistry.");}try {// 創建實現了type接口的代理對象return mapperProxyFactory.newInstance(sqlSession);} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);} }MapperProxyFactory主要負責創建代理對象
@SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy); }2.MapperProxy
MapperProxy實現了InvocationHandler接口,對動態代理的可以先去了解這篇文章https://my.oschina.net/u/3737136/blog/1786175
public class MapperProxy<T> implements InvocationHandler, Serializable {private static final long serialVersionUID = -6424540398559729838L;// 記錄關聯的SQLSession對象private final SqlSession sqlSession;// mapper接口對應的class對象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;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 如果目標方法是Object類繼承來的,直接調用目標方法if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}// 從緩存中獲取MapperMethod 對象,如果沒有就創建新的并添加final MapperMethod mapperMethod = cachedMapperMethod(method);// 執行sql 語句return mapperMethod.execute(sqlSession, args);}}3.MapperMethod
MapperMethod中封裝了Mapper接口中對應方法的信息,以及對應SQL語句的信息,
public class MapperMethod {// 記錄SQL語句的名稱和類型private final SqlCommand command;// mapper接口中對應方法的相關信息private final MethodSignature method;public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new SqlCommand(config, mapperInterface, method);this.method = new MethodSignature(config, mapperInterface, method);}public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {// 處理返回值為void ,ResultSet 通過ResultHand處理的方法executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {// 處理返回值為集合或者數組的方法result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {// 處理返回值為map的方法result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {// 處理返回值為cursor的方法result = executeForCursor(sqlSession, args);} else {// 處理返回值為單一對象的方法Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default: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;} }?
總結
以上是生活随笔為你收集整理的mybatis源码阅读(四):mapper(dao)实例化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样查看笔记本电池损耗情况如何查看电脑电
- 下一篇: Excel如何制作印章如何制作电脑公章