zoukankan      html  css  js  c++  java
  • Mybaits源码分析七之XMLConfigBuilder类mappers标签解析

    根据mybatis配置加载流程 

     1 private void parseConfiguration(XNode root) {
     2     try {
     3       //解析子节点的properties文件
     4       propertiesElement(root.evalNode("properties"));
     5       //加载用户自定义配置
     6       Properties settings = settingsAsProperties(root.evalNode("settings"));
     7       //加载vfs虚拟文件系统配置
     8       loadCustomVfs(settings);
     9      // 解析子节点typeAliases 别名
    10       typeAliasesElement(root.evalNode("typeAliases"));
    11       //解析子节点plugins 插件
    12       pluginElement(root.evalNode("plugins"));
    13       //解析子节点objectFactory mybatis为结果创建对象时都会用到objectFactory
    14       objectFactoryElement(root.evalNode("objectFactory"));
    15       //解析子节点的封装对象
    16       objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    17       reflectorFactoryElement(root.evalNode("reflectorFactory"));
    18       //解析settings标签的文件配置
    19       settingsElement(settings);
    20       //配置运行环境
    21       environmentsElement(root.evalNode("environments"));
    22       //解析子节点配置数据库供应商
    23       databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    24       //解析对象类型处理器,处理Java的pojo类型与数据库类型的映射
    25       typeHandlerElement(root.evalNode("typeHandlers"));
    26       //解析子节点的mappers
    27       mapperElement(root.evalNode("mappers"));
    28     } catch (Exception e) {
    29       throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    30     }
    31   }
     mapperElement(root.evalNode("mappers"));主要解决mappers标签的配置解析,在mybatis中<mappers>写法为:
     1 <!--加载mapper映射 如果将和spring整合后,可以使用整合包中提供的mapper扫描器,此处的mappers不用配置了。 -->
     2  <mappers>
     3 <!-- 通过resource引用mapper的映射文件 -->
     4         <!--<mapper resource="com/ssc/demo/mybatis/mapper/SubjectMapper.xml"/>-->
     5 <!-- <mapper resource="mapper/UserMapper.xml" /> -->
     6         <!--<mapper url="file:///D:workspaceideagitdemo_01srcmainjavacomsscdemomybatismapperSubjectMapper.xml"/>-->
     7 <!-- 通过class引用mapper接口 class:配置mapper接口全限定名 要求:需要mapper.xml和mapper.java同名并且在一个目录 
     8             中 -->
     9         <!--<mapper class="com.ssc.demo.mybatis.dao.SubjectDao"/>-->
    10 <!-- 批量mapper配置 通过package进行自动扫描包下边的mapper接口, 要求:需要mapper.xml和mapper.java同名并且在一个目录 
    11             中 -->
    12         <package name="com.ssc.demo.mybatis.mapper"/>
    13     </mappers>
     mapperElement(root.evalNode("mappers"));方法源码为:
     1 private void mapperElement(XNode parent) throws Exception {
     2     if (parent != null) {
     3       for (XNode child : parent.getChildren()) {
     4      //package扫描方式
     5         if ("package".equals(child.getName())) {
     6           String mapperPackage = child.getStringAttribute("name");
     7           configuration.addMappers(mapperPackage);
     8         } else {
     9           String resource = child.getStringAttribute("resource");
    10           String url = child.getStringAttribute("url");
    11           String mapperClass = child.getStringAttribute("class");
    12           if (resource != null && url == null && mapperClass == null) {
    13 //resource方式
    14             ErrorContext.instance().resource(resource);
    15             InputStream inputStream = Resources.getResourceAsStream(resource);
    16             XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
    17             mapperParser.parse();
    18           } else if (resource == null && url != null && mapperClass == null) {
    19 //URL方式
    20             ErrorContext.instance().resource(url);
    21             InputStream inputStream = Resources.getUrlAsStream(url);
    22             XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
    23             mapperParser.parse();
    24           } else if (resource == null && url == null && mapperClass != null) {
    25      //class 方式
    26             Class<?> mapperInterface = Resources.classForName(mapperClass);
    27             configuration.addMapper(mapperInterface);
    28           } else {
    29             throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
    30           }
    31         }
    32       }
    33     }
    34   }
    通过以上方法得知,四种方式对应两种不同形式的mapper配置解析分别为configuration.addMappers(mapperPackage);和 mapperParser.parse();
    configuration.addMappers(mapperPackage)源码为:
    1  public <T> void addMapper(Class<T> type) {
    2     mapperRegistry.addMapper(type);
    3   }
     1 public <T> void addMapper(Class<T> type) {
     2    //判断这类是否是接口类型
     3     if (type.isInterface()) {
     4    //判断是否已加载
     5       if (hasMapper(type)) {
     6         throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
     7       }
     8       boolean loadCompleted = false;
     9       try {
    10         knownMappers.put(type, new MapperProxyFactory<T>(type));
    11         // It's important that the type is added before the parser is run
    12         // otherwise the binding may automatically be attempted by the
    13         // mapper parser. If the type is already known, it won't try.
    14       //构造一个MapperAnnotationBuilder对象解析这个类
    15         MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
    16         parser.parse();
    17         loadCompleted = true;
    18       } finally {
    19         if (!loadCompleted) {
    20           knownMappers.remove(type);
    21         }
    22       }
    23     }
    24   }
    parser.parse();方法源码为:
     1 public void parse() {
     2     String resource = type.toString();
     3 //判断是否已加载此  配置的例如(USERDAO) 接口
     4     if (!configuration.isResourceLoaded(resource)) {
     5 //  加载与此类同名的xml类型mapper文件
     6       loadXmlResource();
     7 //将该资源加入到全局配置
     8       configuration.addLoadedResource(resource);
     9 //设置当前命名空间
    10       assistant.setCurrentNamespace(type.getName());
    11 //解析二级缓存
    12       parseCache();
    13       parseCacheRef();
    14    //获取类中的所以的方法
    15       Method[] methods = type.getMethods();
    16       for (Method method : methods) {
    17         try {
    18           // 判断该方法是否是桥接方法,桥接方法指的是由编译器自动生成的方法
    19           if (!method.isBridge()) {
    20         //解析statement
    21             parseStatement(method);
    22           }
    23         } catch (IncompleteElementException e) {
    24 //将异常解析的方法加入一个List中
    25           configuration.addIncompleteMethod(new MethodResolver(this, method));
    26         }
    27       }
    28     }
    29 //解析挂起的方法
    30     parsePendingMethods();
    31   }
      loadXmlResource();是加载同级包下面的同名的xml配置文件,其源码为
     1   private void loadXmlResource() {
     2     // 判断此资源是否已经加载,防止加载两次
     3     if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
     4 //将此类的全限类名的路径替换
     5       String xmlResource = type.getName().replace('.', '/') + ".xml";
     6       InputStream inputStream = null;
     7       try {
     8 //加载同名的xml类型的mapper文件
     9         inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
    10       } catch (IOException e) {
    11         // ignore, resource is not required
    12       }
    13       if (inputStream != null) {
    14         XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
    15       //xml文件解析
    16         xmlParser.parse();
    17       }
    18     }
    19   }
     xmlParser.parse();是对mapper.xml文件解析。源码分析为
    --------------------------------------------------------
    start xmlParser----------------------------------------------------------------------------------

     1  public void parse() {
     2    //判断该资源是否已加载
     3     if (!configuration.isResourceLoaded(resource)) {
     4     //加载mapper.xml文件下的mapper节点
     5       configurationElement(parser.evalNode("/mapper"));
     6     //加载配置
     7       configuration.addLoadedResource(resource);
     8    //mapper绑定命名空间
     9       bindMapperForNamespace();
    10     }
    11     //解析待定的ResultMaps
    12     parsePendingResultMaps();
    13    //解析待定的缓存
    14     parsePendingCacheRefs();
    15    //解析待定的Statements
    16     parsePendingStatements();
    17   }

     configurationElement(parser.evalNode("/mapper"));源码为

     1   private void configurationElement(XNode context) {
     2     try {
     3       String namespace = context.getStringAttribute("namespace");
     4       if (namespace == null || namespace.equals("")) {
     5         throw new BuilderException("Mapper's namespace cannot be empty");
     6       }
     7 //设置命名空间
     8       builderAssistant.setCurrentNamespace(namespace);
     9       //引用其他namespace的二级缓存
    10       cacheRefElement(context.evalNode("cache-ref"));
    11      //引用当前namespace的二级缓存
    12       cacheElement(context.evalNode("cache"));
    13     //parameterMap节点解析     
    parameterMapElement(context.evalNodes("/mapper/parameterMap"));
    14 //resultMap节点解析 15 resultMapElements(context.evalNodes("/mapper/resultMap")); 16 //sql片段节点解析 17 sqlElement(context.evalNodes("/mapper/sql")); 18 //构建statement 19 buildStatementFromContext(context.evalNodes("select|insert|update|delete")); 20 } catch (Exception e) { 21 throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e); 22 } 23 }
     1 /**
     2    *主要将parameterMap节点下的各参数值获取,得到 
     3  *ParameterMapping对象,再放到parameterMappings列表中
     4 */
     5 private void parameterMapElement(List<XNode> list) throws Exception {
     6     for (XNode parameterMapNode : list) {
     7       String id = parameterMapNode.getStringAttribute("id");
     8       String type = parameterMapNode.getStringAttribute("type");
     9       Class<?> parameterClass = resolveClass(type);
    10       List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
    11       List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
    12       for (XNode parameterNode : parameterNodes) {
    13         String property = parameterNode.getStringAttribute("property");
    14         String javaType = parameterNode.getStringAttribute("javaType");
    15         String jdbcType = parameterNode.getStringAttribute("jdbcType");
    16         String resultMap = parameterNode.getStringAttribute("resultMap");
    17         String mode = parameterNode.getStringAttribute("mode");
    18         String typeHandler = parameterNode.getStringAttribute("typeHandler");
    19         Integer numericScale = parameterNode.getIntAttribute("numericScale");
    20         ParameterMode modeEnum = resolveParameterMode(mode);
    21         Class<?> javaTypeClass = resolveClass(javaType);
    22         JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
    23         @SuppressWarnings("unchecked")
    24         Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
    25         ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
    26         parameterMappings.add(parameterMapping);
    27       }
    28       builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
    29     }
    30   }
     1  private void resultMapElements(List<XNode> list) throws Exception {
     2     for (XNode resultMapNode : list) {
     3       try {
     4         resultMapElement(resultMapNode);
     5       } catch (IncompleteElementException e) {
     6         // ignore, it will be retried
     7       }
     8     }
     9   }
    10 
    11   private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
    12     return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
    13   }
    14 
    15   private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
    16     ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    17     String id = resultMapNode.getStringAttribute("id",
    18         resultMapNode.getValueBasedIdentifier());
    19     String type = resultMapNode.getStringAttribute("type",
    20         resultMapNode.getStringAttribute("ofType",
    21             resultMapNode.getStringAttribute("resultType",
    22                 resultMapNode.getStringAttribute("javaType"))));
    23     String extend = resultMapNode.getStringAttribute("extends");
    24     Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    25     Class<?> typeClass = resolveClass(type);
    26     Discriminator discriminator = null;
    27     List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
    28     resultMappings.addAll(additionalResultMappings);
    29     List<XNode> resultChildren = resultMapNode.getChildren();
    30     for (XNode resultChild : resultChildren) {
    31       if ("constructor".equals(resultChild.getName())) {
    32         processConstructorElement(resultChild, typeClass, resultMappings);
    33       } else if ("discriminator".equals(resultChild.getName())) {
    34         discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
    35       } else {
    36         List<ResultFlag> flags = new ArrayList<ResultFlag>();
    37         if ("id".equals(resultChild.getName())) {
    38           flags.add(ResultFlag.ID);
    39         }
    40         resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
    41       }
    42     }
    43     ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    44     try {
    45       return resultMapResolver.resolve();
    46     } catch (IncompleteElementException  e) {
    47       configuration.addIncompleteResultMap(resultMapResolver);
    48       throw e;
    49     }
    50   }
     1  private void sqlElement(List<XNode> list) throws Exception {
     2     if (configuration.getDatabaseId() != null) {
     3       sqlElement(list, configuration.getDatabaseId());
     4     }
     5     sqlElement(list, null);
     6   }
     7 
     8   private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
     9     for (XNode context : list) {
    10       String databaseId = context.getStringAttribute("databaseId");
    11       String id = context.getStringAttribute("id");
    12       id = builderAssistant.applyCurrentNamespace(id, false);
    13       if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
    14         sqlFragments.put(id, context);
    15       }
    16     }
    17   }
     1  public void parseStatementNode() {
     2     String id = context.getStringAttribute("id");
     3     String databaseId = context.getStringAttribute("databaseId");
     4 
     5     if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
     6       return;
     7     }
     8      //指的是一次获取结果数量大小
     9     Integer fetchSize = context.getIntAttribute("fetchSize");
    10     Integer timeout = context.getIntAttribute("timeout");
    11     String parameterMap = context.getStringAttribute("parameterMap");
    12     String parameterType = context.getStringAttribute("parameterType");
    13     Class<?> parameterTypeClass = resolveClass(parameterType);
    14     String resultMap = context.getStringAttribute("resultMap");
    15     String resultType = context.getStringAttribute("resultType");
    16     String lang = context.getStringAttribute("lang");
    17     LanguageDriver langDriver = getLanguageDriver(lang);
    18     Class<?> resultTypeClass = resolveClass(resultType);
    19     String resultSetType = context.getStringAttribute("resultSetType");
    20     //判断标签中是否指定了statementType参数,如果没有默认为预编译,主要有三种 STATEMENT, PREPARED, CALLABLE选择
    21     StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    22     ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    23     //获取节点名称
    24     String nodeName = context.getNode().getNodeName();
    25     SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    26     boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    27     boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    28     boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    29     boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
    30 
    31     // Include Fragments before parsing 先解析sql片段
    32     XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    33     includeParser.applyIncludes(context.getNode());
    34 
    35     // Parse selectKey after includes and remove them.
    36     processSelectKeyNodes(id, parameterTypeClass, langDriver);
    37     
    38     // Parse the SQL (pre: <selectKey> and <include> were parsed and removed),创建sql资源(包含了sql语句,参数,配置)
    39     SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    40     String resultSets = context.getStringAttribute("resultSets");
    41     String keyProperty = context.getStringAttribute("keyProperty");
    42     String keyColumn = context.getStringAttribute("keyColumn");
    43     KeyGenerator keyGenerator;
    44     //statementId 类型为“com.ssc.demo.mybatis.dao.SubjectDao.selectSubjects!selectKey”
    45     String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    46     keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    47     if (configuration.hasKeyGenerator(keyStatementId)) {
    48       keyGenerator = configuration.getKeyGenerator(keyStatementId);
    49     } else {
    50       keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
    51           configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
    52           ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    53     }
    54 
    55     builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
    56         fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
    57         resultSetTypeEnum, flushCache, useCache, resultOrdered, 
    58         keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
    59   }

    --------------------------------------------------------------------------------------------------end ---------------------------------------------------------------------------------------------------------------------------------------------

     
     
     
     
     


    生于忧患,死于安乐
  • 相关阅读:
    【SAS NOTE】OUTPUT
    【SAS NOTES】_NULL_
    【SAS NOTE】sas 9.2 安装
    【SAS NOTE】FREQ
    纯数学教程 Page 203 例XLI (1)
    纯数学教程 Page 203 例XLI (3)
    纯数学教程 Page 203 例XLI (2)
    Prove Cauchy's inequality by induction
    纯数学教程 Page 325 例LXVIII (15) 调和级数发散
    纯数学教程 Page 325 例LXVIII (15) 调和级数发散
  • 原文地址:https://www.cnblogs.com/songlove/p/14607610.html
Copyright © 2011-2022 走看看