`
shuidexiongdi
  • 浏览: 73261 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Ibatis源码学习(三):配置文件的解析

 
阅读更多

ibatis文件的文件的解析从主文件sql-map-config.xml开始。见类:com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser

 

public SqlMapConfigParser() {
    parser.setValidation(true);
    parser.setEntityResolver(new SqlMapClasspathEntityResolver());

    addSqlMapConfigNodelets();             //"/sqlMapConfig/end()"
    addGlobalPropNodelets();                 //"/sqlMapConfig/properties"
    addSettingsNodelets();                     //"/sqlMapConfig/settings"
    addTypeAliasNodelets();                   //"/sqlMapConfig/typeAlias"
    addTypeHandlerNodelets();              //"/sqlMapConfig/typeHandler"
    addTransactionManagerNodelets();  //"/sqlMapConfig/transactionManager/property" ...
    addSqlMapNodelets();                       //"/sqlMapConfig/sqlMap"
    addResultObjectFactoryNodelets();   //"/sqlMapConfig/resultObjectFactory" ...

  }

先将上诉的节点默认添加进来,然后根据具体的设置在利用回调来初始化各个节点的具体属性值,以addSettingsNodelets()为例:

 

 private void addSettingsNodelets() {
    parser.addNodelet("/sqlMapConfig/settings", new Nodelet() {
      public void process(Node node) throws Exception { //该方法做会调用
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        SqlMapConfiguration config = state.getConfig();

        String classInfoCacheEnabledAttr = attributes.getProperty("classInfoCacheEnabled");
        boolean classInfoCacheEnabled = (classInfoCacheEnabledAttr == null || "true".equals(classInfoCacheEnabledAttr));
        config.setClassInfoCacheEnabled(classInfoCacheEnabled);

        String lazyLoadingEnabledAttr = attributes.getProperty("lazyLoadingEnabled");
        boolean lazyLoadingEnabled = (lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr));
        config.setLazyLoadingEnabled(lazyLoadingEnabled);

        String statementCachingEnabledAttr = attributes.getProperty("statementCachingEnabled");
        boolean statementCachingEnabled = (statementCachingEnabledAttr == null || "true".equals(statementCachingEnabledAttr));
        config.setStatementCachingEnabled(statementCachingEnabled);

        String cacheModelsEnabledAttr = attributes.getProperty("cacheModelsEnabled");
        boolean cacheModelsEnabled = (cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr));
        config.setCacheModelsEnabled(cacheModelsEnabled);

        String enhancementEnabledAttr = attributes.getProperty("enhancementEnabled");
        boolean enhancementEnabled = (enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr));
        config.setEnhancementEnabled(enhancementEnabled);

        String useColumnLabelAttr = attributes.getProperty("useColumnLabel");
        boolean useColumnLabel = (useColumnLabelAttr == null || "true".equals(useColumnLabelAttr));
        config.setUseColumnLabel(useColumnLabel);

        String forceMultipleResultSetSupportAttr = attributes.getProperty("forceMultipleResultSetSupport");
        boolean forceMultipleResultSetSupport = "true".equals(forceMultipleResultSetSupportAttr);
        config.setForceMultipleResultSetSupport(forceMultipleResultSetSupport);

        String defaultTimeoutAttr = attributes.getProperty("defaultStatementTimeout");
        Integer defaultTimeout = defaultTimeoutAttr == null ? null : Integer.valueOf(defaultTimeoutAttr);
        config.setDefaultStatementTimeout(defaultTimeout);

        String useStatementNamespacesAttr = attributes.getProperty("useStatementNamespaces");
        boolean useStatementNamespaces = "true".equals(useStatementNamespacesAttr);
        state.setUseStatementNamespaces(useStatementNamespaces);
      }
    });
  }

 parser.addNodelet(xpath,nodelet)添加一个节点,见类:com.ibatis.common.xml.NodeletParser

 

 public void addNodelet(String xpath, Nodelet nodelet) {
    letMap.put(xpath, nodelet);
  }

在这个类中,解析节点的时候,

 

  public void parse(Reader reader) throws NodeletException {
    try {
      Document doc = createDocument(reader);
      parse(doc.getLastChild());
    } catch (Exception e) {
      throw new NodeletException("Error parsing XML.  Cause: " + e, e);
    }
  }

  public void parse(InputStream inputStream) throws NodeletException {
    try {
      Document doc = createDocument(inputStream);
      parse(doc.getLastChild());
    } catch (Exception e) {
      throw new NodeletException("Error parsing XML.  Cause: " + e, e);
    }
  }
  
  /**
   * Begins parsing from the provided Node.
   */
  public void parse(Node node) {
    Path path = new Path();
    processNodelet(node, "/");
    process(node, path);
  }

  /**
   * A recursive method that walkes the DOM tree, registers XPaths and
   * calls Nodelets registered under those XPaths.
   */
  private void process(Node node, Path path) {
    if (node instanceof Element) {
      // Element
      String elementName = node.getNodeName();
      path.add(elementName);
      processNodelet(node, path.toString());
      processNodelet(node, new StringBuffer("//").append(elementName).toString());

      // Attribute
      NamedNodeMap attributes = node.getAttributes();
      int n = attributes.getLength();
      for (int i = 0; i < n; i++) {
        Node att = attributes.item(i);
        String attrName = att.getNodeName();
        path.add("@" + attrName);
        processNodelet(att, path.toString());
        processNodelet(node, new StringBuffer("//@").append(attrName).toString());
        path.remove();
      }

      // Children
      NodeList children = node.getChildNodes();
      for (int i = 0; i < children.getLength(); i++) {
        process(children.item(i), path);
      }
      path.add("end()");
      processNodelet(node, path.toString());
      path.remove();
      path.remove();
    } else if (node instanceof Text) {
      // Text
      path.add("text()");
      processNodelet(node, path.toString());
      processNodelet(node, "//text()");
      path.remove();
    }
  }

  private void processNodelet(Node node, String pathString) {
    Nodelet nodelet = (Nodelet) letMap.get(pathString);
    if (nodelet != null) { 
      try {
        nodelet.process(node); //这个方法进行回调,设置初始值
      } catch (Exception e) {
        throw new RuntimeException("Error parsing XPath '" + pathString + "'.  Cause: " + e, e);
      }
    }
  }
 

在com.ibatis.sqlmap.engine.builder.xml.SqlMapParser里面解析到statement时:

 protected void addStatementNodelets() {
    parser.addNodelet("/sqlMap/statement", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new MappedStatement());
      }
    });
    parser.addNodelet("/sqlMap/insert", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new InsertStatement());
      }
    });
    parser.addNodelet("/sqlMap/update", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new UpdateStatement());
      }
    });
    parser.addNodelet("/sqlMap/delete", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new DeleteStatement());
      }
    });
    parser.addNodelet("/sqlMap/select", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new SelectStatement());
      }
    });
    parser.addNodelet("/sqlMap/procedure", new Nodelet() {
      public void process(Node node) throws Exception {
        statementParser.parseGeneralStatement(node, new ProcedureStatement());
      }
    });
  }
 实际上调用了com.ibatis.sqlmap.engine.builder.xml.SqlStatementParser的parseGeneralStatement方法:

public void parseGeneralStatement(Node node, MappedStatement statement) {

    // ...

    MappedStatementConfig statementConf = state.getConfig().newMappedStatementConfig(id, statement,
        new XMLSqlSource(state, node), parameterMapName, parameterClass, resultMapName, additionalResultMapNames,
        resultClass, additionalResultClasses, resultSetType, fetchSizeInt, allowRemappingBool, timeoutInt, cacheModelName,
        xmlResultName);

    findAndParseSelectKey(node, statementConf);
  }
 此时又是调用了com.ibatis.sqlmap.engine.config.SqlMapConfiguration的newMappedStatementConfig方法:

public MappedStatementConfig newMappedStatementConfig(String id, MappedStatement statement, SqlSource processor,
                                                        String parameterMapName, Class parameterClass,
                                                        String resultMapName, String[] additionalResultMapNames,
                                                        Class resultClass, Class[] additionalResultClasses, 
                                                        String resultSetType, Integer fetchSize,
                                                        boolean allowRemapping, Integer timeout, String cacheModelName,
                                                        String xmlResultName) {
    return new MappedStatementConfig(this, id, statement, processor, parameterMapName, parameterClass, resultMapName,
        additionalResultMapNames, resultClass, additionalResultClasses, cacheModelName, resultSetType, fetchSize,
        allowRemapping, timeout, defaultStatementTimeout, xmlResultName);
  }
 返回一个com.ibatis.sqlmap.engine.config.MappedStatementConfig的实例

MappedStatementConfig(SqlMapConfiguration config, String id, MappedStatement statement, SqlSource processor,
                        String parameterMapName, Class parameterClass, String resultMapName,
                        String[] additionalResultMapNames, Class resultClass, Class[] additionalResultClasses,
                        String cacheModelName, String resultSetType, Integer fetchSize, boolean allowRemapping,
                        Integer timeout, Integer defaultStatementTimeout, String xmlResultName) {
    this.errorContext = config.getErrorContext();
    this.client = config.getClient();
    SqlMapExecutorDelegate delegate = client.getDelegate();
    this.typeHandlerFactory = config.getTypeHandlerFactory();
    errorContext.setActivity("parsing a mapped statement");
    errorContext.setObjectId(id + " statement");
    errorContext.setMoreInfo("Check the result map name.");
    if (resultMapName != null) {
      statement.setResultMap(client.getDelegate().getResultMap(resultMapName));
      if (additionalResultMapNames != null) {
        for (int i = 0; i < additionalResultMapNames.length; i++) {
          statement.addResultMap(client.getDelegate().getResultMap(additionalResultMapNames[i]));
        }
      }
    }
    errorContext.setMoreInfo("Check the parameter map name.");
    if (parameterMapName != null) {
      statement.setParameterMap(client.getDelegate().getParameterMap(parameterMapName));
    }
    statement.setId(id);
    statement.setResource(errorContext.getResource());
    if (resultSetType != null) {
      if ("FORWARD_ONLY".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_FORWARD_ONLY));
      } else if ("SCROLL_INSENSITIVE".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_INSENSITIVE));
      } else if ("SCROLL_SENSITIVE".equals(resultSetType)) {
        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_SENSITIVE));
      }
    }
    if (fetchSize != null) {
      statement.setFetchSize(fetchSize);
    }

    // set parameter class either from attribute or from map (make sure to match)
    ParameterMap parameterMap = statement.getParameterMap();
    if (parameterMap == null) {
      statement.setParameterClass(parameterClass);
    } else {
      statement.setParameterClass(parameterMap.getParameterClass());
    }

    // process SQL statement, including inline parameter maps
    errorContext.setMoreInfo("Check the SQL statement.");
    Sql sql = processor.getSql();
    setSqlForStatement(statement, sql);

    // set up either null result map or automatic result mapping
    ResultMap resultMap = (ResultMap) statement.getResultMap();
    if (resultMap == null && resultClass == null) {
      statement.setResultMap(null);
    } else if (resultMap == null) {
      resultMap = buildAutoResultMap(allowRemapping, statement, resultClass, xmlResultName);
      statement.setResultMap(resultMap);
      if (additionalResultClasses != null) {
        for (int i = 0; i < additionalResultClasses.length; i++) {
          statement.addResultMap(buildAutoResultMap(allowRemapping, statement, additionalResultClasses[i], xmlResultName));
        }
      }

    }
    statement.setTimeout(defaultStatementTimeout);
    if (timeout != null) {
      try {
        statement.setTimeout(timeout);
      } catch (NumberFormatException e) {
        throw new SqlMapException("Specified timeout value for statement " + statement.getId() + " is not a valid integer");
      }
    }
    errorContext.setMoreInfo(null);
    errorContext.setObjectId(null);
    statement.setSqlMapClient(client);
    if (cacheModelName != null && cacheModelName.length() > 0 && client.getDelegate().isCacheModelsEnabled()) {//这个判断很关键
      CacheModel cacheModel = client.getDelegate().getCacheModel(cacheModelName);
      mappedStatement = new CachingStatement(statement, cacheModel);
    } else {
      mappedStatement = statement;
    }
    rootStatement = statement;
    delegate.addMappedStatement(mappedStatement);
  }

 上诉的if (cacheModelName != null && cacheModelName.length() > 0 && client.getDelegate().isCacheModelsEnabled())判断,直接决定了是否启用缓存,假设前面没有设置setting这个属性,该值是为空的,不存在默认值,故此时是不会启用缓存的。

 

总结:

当解析实际的配置文件sql-map-config.xml时,

如果设置了<setting>这个属性,则回调addSettingsNodelets里面的addNodelet里面的Nodelet的process方法。

设置里面的属性值,假如此时没有设置<setting>属性(注意,是没有设置,不是设置为空,因为设置为空,同样的调用回调,设置了默认值),则不再调用此回调函数,则此时将没有默认值,如果此时想启动缓存等,都是无效的。

   故,此时应注意,如果想利用默认值,setting是必须设置的,哪怕设置为空。但,如果设置了setting后,文件的先后顺序是有要求的,如果A文件利用到b文件的命名空间的某个引用id,则此时必须使得B文件在A文件之前装载,否则将出现文件A引用文件B中的id时出现不存在的异常。

 

分享到:
评论

相关推荐

    ibatis源码

    - **iBATIS SQLMap-2.3.4.726**:这是iBATIS的主程序包,包含了框架的主要类和接口,以及相关的配置文件。 - **iBATIS Extended**:可能是iBATIS的扩展组件或者第三方对iBATIS的增强版,增加了额外的功能或优化。 - ...

    ibatis源码,ibatis源码 ibatis源码 ibatis源码

    《深入解析iBatis源码》 iBatis,一个优秀的Java持久层框架,以其轻量级、灵活的特性在众多ORM(Object-Relational Mapping)框架中独树一帜。iBatis的核心在于它的SQL映射机制,它将数据库操作与业务逻辑解耦,...

    ibatis2.3源码

    1. **SqlMapConfig.xml**:这是iBATIS的核心配置文件,包含了数据源、事务管理器、SqlMapClient以及全局设置等信息。 2. **MappedStatement**:每个SQL语句在iBATIS中都对应一个MappedStatement对象,包含了SQL语句...

    ibatisDemo 入门源码

    Ibatis,一个优秀的持久层框架,它允许开发者将SQL语句直接写在配置文件中,避免了JDBC的繁琐代码,提升了开发效率。接下来,我们将深入探讨IbatisDemo中的关键知识点。 一、Ibatis框架简介 Ibatis是由MyBatis团队...

    ibatis学习资料汇总

    深入研究iBatis源码有助于理解其内部工作原理,包括如何解析XML配置文件,如何执行SQL语句,以及如何进行结果映射。源码分析可以帮助开发者更好地定制和优化自己的应用。 六、iBatis实践项目 通过实践项目,可以...

    ibatis框架源码剖析光盘资料

    《ibatis框架源码剖析》是一本深入探讨mybatis前身——ibatis的源码解析书籍。通过对源码的深入分析,我们可以理解ibatis的核心机制,掌握数据库操作的底层原理,从而更好地利用和优化这个强大的持久层框架。在这个...

    ibatis学习

    标题 "ibatis学习" 暗示我们即将探讨的是关于Ibatis,一个著名的Java持久层框架,它允许开发者将SQL语句直接写在配置文件中,以实现灵活的数据访问。Ibatis提供了简单易用的API,使得数据库操作与业务逻辑解耦,提高...

    springMVC+ibatis的源码

    iBatis的亮点在于它的XML配置文件,开发者可以在其中编写SQL语句,并通过动态参数绑定,实现灵活的数据查询。此外,iBatis支持ResultMap,可以方便地映射查询结果到Java对象,避免了过多的手动类型转换。通过...

    iBATIS框架源码剖析pdf第二部分

    在源码分析部分,你会看到iBATIS如何加载和解析XML配置文件,如何执行SQL语句,以及如何处理异常。这部分内容对于理解iBATIS的工作流程至关重要,它将帮助你更好地调试和优化基于iBATIS的应用。 最后,你会了解到...

    ibatis2.X升级mybatis3.X之曲径通幽处

    Ibatis2.x是一款轻量级的ORM框架,它允许开发者通过SQL Map配置文件来编写SQL语句,提供了灵活的SQL控制。然而,随着技术的发展,Mybatis3.x应运而生,它在Ibatis的基础上进行了诸多改进和优化。 首先,从版本号的...

    iBatis 课件 源码 资源文件.rar

    1. **SQL映射文件**:iBatis的核心在于XML配置文件,其中包含了SQL语句和参数映射。这使得开发者能够自由地编写复杂的SQL,而不需要在Java代码中嵌入大量的字符串拼接。 2. **动态SQL**:iBatis支持动态SQL,可以在...

    ibatis.rar学习手册

    9. **源码解析**:对于对底层原理感兴趣的开发者,可能包含iBatis源码的解读,帮助理解其工作原理。 10. **进阶内容**:可能涵盖MyBatis(iBatis的升级版)的特性,以及如何使用插件扩展iBatis功能。 通过深入学习...

    ibatis实战之基础环境搭建(源码).zip

    - 如何解析SqlMapConfig.xml配置文件,创建SqlSessionFactory? - SqlSession是如何管理数据库会话的? - Executor接口及其实现如何处理SQL执行? - 参数和结果是如何通过ParameterHandler和ResultHandler进行映射的...

    ibatis源代码项目

    三、XML映射文件解析 iBatis通过解析XML映射文件来获取SQL语句和参数映射信息。映射文件包含以下关键元素: - `&lt;mapper&gt;`:定义一个Mapper接口,映射到特定的XML文件。 - `&lt;select&gt;`、`&lt;insert&gt;`、`&lt;update&gt;`、`...

    根据mybatis/ibatis sqlmapper文件解析生成数据库表

    标题 "根据mybatis/ibatis sqlmapper文件解析生成数据库表" 暗示了我们将会探讨一个关于MyBatis或iBatis框架的工具,它能够解析SQL映射文件并根据这些文件自动生成数据库表。这个过程对于快速构建数据库模型,尤其是...

    ibatis3源码+驱动

    《深入解析iBatis3:源码与驱动详解》 iBatis3作为一个轻量级的持久层框架,因其灵活性和高效性,在Java开发中备受青睐。本文将围绕标题"ibatis3源码+驱动",对iBatis3的核心功能、设计理念、源码结构以及驱动机制...

    ibatis 框架源码剖析 书籍源代码 带有详尽注释

    映射文件允许灵活地配置参数,支持动态SQL,比如根据条件选择性地执行某个部分。 3. SQL Session:SQL Session是iBATIS与数据库进行交互的接口,负责执行SQL语句并管理事务。一个Session对应一次数据库连接,用于...

    ibatis2.3.4.726增删改查源码实例

    Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,将Java对象与数据库之间的交互转换为易于管理的XML或注解配置文件,从而减轻了开发者编写繁琐的手动SQL和结果集映射的工作。在本实例中,...

    Ibatis和Mybatis实例源码

    Ibatis的核心概念是SqlMapConfig.xml配置文件,它包含了数据源、事务管理器等关键设置。在源码中,可以看到Ibatis如何通过SqlSessionFactory构建会话工厂,以及SqlSession接口如何处理数据库交互。SqlMapper接口提供...

Global site tag (gtag.js) - Google Analytics