zoukankan      html  css  js  c++  java
  • 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对象的代理。

  • 相关阅读:
    Java IO输入输出流 FileWriter 字符流
    Java IO输入输出流File 字节流
    Java List集合和Map集合的综合应用
    表单提交中的重复问题(表单令牌验证)
    php中const与define的区别
    阿里云中获取文件及目录列表的方法
    巧用php中的array_filter()函数去掉多维空值
    文件大小格式化函数
    UTC 通用格式时间 转换为 时间戳,并格式化为2017-01-01 12:00:00
    关于匿名函数的使用,购物车中计算销售税的应用
  • 原文地址:https://www.cnblogs.com/zsg88/p/7550901.html
Copyright © 2011-2022 走看看