我們先Mapper接口的調用方式,見<MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置與使用>的示例:
public void findUserById() {
SqlSessionFactory sqlSessionFactory = getSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectByPrimaryKey(1l); System.out.println(user.getId() + " / " + user.getName()); }
sqlsession.getMapper(UserMapper.class) 也就是調用DefaultSqlSession的對應方法:
public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); }
繼續跟蹤Configuration對象對應源碼:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
我們在回憶,在 <MyBatis框架中Mapper映射配置的使用及原理解析(四) 解析Mapper接口映射xml文件> 一文,我們知道在讀取mapper xml文件后會調用org.apache.ibatis.builder.xml.XMLMapperBuilder類的bindMapperForNamespace()方法,綁定到命名空間:
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#loadXmlResource configuration.addLoadedResource("namespace:" + namespace);//添加資源標識 configuration.addMapper(boundType); //Mapper接口添加到Configuration } } } }
繼續跟蹤configuration.addMapper(boundType)方法:
public <T> void addMapper(Class<T> type) { mapperRegistry.addMapper(type); }
我們發現添加和獲取Mapper實例都使用到了同一個類MapperRegistry,在Configuration中的聲明如下:
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
下面貼出MapperRegistry的源代碼:
package org.apache.ibatis.binding; import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder; import org.apache.ibatis.io.ResolverUtil; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapperRegistry { private Configuration config; private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>(); public MapperRegistry(Configuration config) { this.config = config; } @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); } } public <T> boolean hasMapper(Class<T> type) { return knownMappers.containsKey(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)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } } /** * @since 3.2.2 */ public Collection<Class<?>> getMappers() { return Collections.unmodifiableCollection(knownMappers.keySet()); } /** * @since 3.2.2 */ public void addMappers(String packageName, Class<?> superType) { ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>(); resolverUtil.find(new ResolverUtil.IsA(superType), packageName); Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses(); for (Class<?> mapperClass : mapperSet) { addMapper(mapperClass); } } /** * @since 3.2.2 */ public void addMappers(String packageName) { addMappers(packageName, Object.class); } }
我們清楚的看到注冊Mapper和獲取Mapper都是在一個Map對象中存取Mapper的代理對象MapperProxyFactory。
經過這篇文章,我們清楚的知道了MapperRegistry的功能就是注冊和獲取Mapper對象的代理。