MyBatis框架的使用及源碼分析(六) MapperRegistry


我們先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對象的代理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM