前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MyBatis入门到源码分析 | 【Mybatis加载核心配置文件流程】

MyBatis入门到源码分析 | 【Mybatis加载核心配置文件流程】

作者头像
青山师
发布2023-05-05 19:41:27
2870
发布2023-05-05 19:41:27
举报
文章被收录于专栏:IT当时语_青山师_JAVA技术栈

Mybatis入门案例

创建maven工程,引入依赖配置项

pom.xml中引入maven依赖:

代码语言:javascript
复制
<dependencies>
        <!--MyBatis坐标-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
</dependencies>

数据库

代码语言:javascript
复制
CREATE DATABASE mybatis;
USE mybatis;

CREATE TABLE `t_user` (
  `uid` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(40) DEFAULT NULL,
  `sex` VARCHAR(10) DEFAULT NULL,
  `birthday` DATE DEFAULT NULL,
  `address` VARCHAR(40) DEFAULT NULL,
  `level` VARCHAR(10) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=INNODB  DEFAULT CHARSET=utf8;


insert  into `t_user`(`uid`,`username`,`sex`,`birthday`,`address`,`level`) values (1,'zs','男','2018-08-08','北京','LOW'),(2,'ls','女','2018-08-30','武汉','MIDDLE'),(3,'ww','男','2018-08-08','北京','LOW');

javabean

User.java类

代码语言:javascript
复制
public class User implements Serializable {
    private int uid; //用户id
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
    // get、set...
}

jdbc.properties

代码语言:javascript
复制
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=root

mybatis核心配置文件

resources目录下创建:mybatis-config.xml,并写入以下内容:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 引入外部配置文件 -->
    <properties resource="jdbc.properties" />

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="useActualParamName" value="true"/>
        <setting name="logImpl" value="SLF4J"/>
        <!-- 自定义的VFS -->
        <setting name="vfsImpl" value="org.byron4j.vfs.MyVFS"/>
    </settings>



    <!--别名方式一:单个-->
    <typeAliases>
        <typeAlias alias="user2" type="org.byron4j.bean.User"/>
        <typeAlias alias="int" type="java.lang.Integer"/>

        <!--方式二,该包下的所有类都默认取别名为类名,并且不区分大小写
            如:  org.byron4j.bean.Product 别名将为  product、Product、ProDuCt  都可以
        -->
        <package name="org.byron4j.bean"/>
    </typeAliases>

    
    <typeHandlers>
        <!--方式一: 单个处理器-->
        <!--<typeHandler handler="org.byron4j.handler.MyHandler" javaType="org.byron4j.bean.User"/>-->
        

        <typeHandler handler="org.byron4j.handler.MyDateHandler" javaType="long" jdbcType="TIMESTAMP"/>

        <!--统一自动查找-->
        <package name="org.byron4j.handler"/>
    </typeHandlers>

    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--<databaseIdProvider type="DB_VENDOR" />-->


    <mappers>
        <mapper resource="org/byron4j/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

mapper.xml映射文件

resources目录下创建目录org/byron4j/mapper目录(注意该目录需要和接口的包层级一致),新建一个UserMapper.xml,写入以下内容:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace: 名称空间,接口的全限定名-->
 <mapper namespace="org.byron4j.mapper.UserMapper">
    <!--
        id属性: 和接口的方法名一致
        resultType属性:返回类型,写全限定名,集合则写元素的泛型类型
        标签体:sql语句
    -->
     <!-- 这里使用了别名User01不区分大小写;只有一个参数时可以随便写参数名比如这里aaa,但是实际开发中建议和参数名保持一致 -->
    <select id="findById" resultType="User01">
        select *  from t_user where uid = #{aaa}
    </select>

</mapper>

Mapper.java接口

org.byron4j.mapper创建一个接口:UserMapper.java

代码语言:javascript
复制
public interface UserDao {

    User findById(Integer id);
}

测试类

编写一个测试类:

代码语言:javascript
复制
@Test
    public void test() throws Exception {


        // 1. 读取配置文件作为流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        // 2. 根据核心配置文件获取SqlSessionFactory对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);


        
        // 3.获取SqlSession对象(类似connection)
        SqlSession sqlSession = build.openSession();
        // 4. 获取代理对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        // 5. 操作,释放资源
        User user = mapper.findById(2);
        System.out.println(user);
        sqlSession.close();
        is.close();
    }

这是一个简单入门案例,会用了之后。我们就可以来学习Mybatis加载核心配置文件流程了。

Mybatis加载核心配置文件流程

1.入口

org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String) 这个方法第一个参数是一个mybatis配置文件代表的输入流;第二个参数是环境,这里我们缺省。

它调用了下面的方法: org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String, java.util.Properties)

在我们的案例中只有第一个参数有值,后面的都是null。

下面开始跟踪源代码

代码语言:javascript
复制
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
	  // 创建一个【XMLConfigBuilder】解析器类
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
}

2.创建一个【XMLConfigBuilder】解析器类

继续跟踪org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder(核心配置xml文件, 环境env, 不指定properties则为null) 方法:

代码语言:javascript
复制
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()),
         environment, props);
  }

方法体又调用了重载构造器:org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder(org.apache.ibatis.parsing.XPathParser, java.lang.String, java.util.Properties) 这里的第一个参数是一个XPathParser类型的解析器(看名字知道是XPath的解析器)。

这里用到了XPathParser构造器,我们接下来看看。

3.【XPathParser】解析器的构造器

构造器:org.apache.ibatis.parsing.XPathParser#XPathParser(java.io.InputStream, true, java.util.Properties为null, org.xml.sax.EntityResolver) 第四个参数是一个实体解析器:org.apache.ibatis.builder.xml.XMLMapperEntityResolver,实现了org.xml.sax.EntityResolver 接口;

所以我们又需要来查看一下XMLMapperEntityResolver这个类是啥玩意。

4.【XMLMapperEntityResolver】实体解析器

org.apache.ibatis.builder.xml.XMLMapperEntityResolver,实现了org.xml.sax.EntityResolver 接口;实现这个接口后,可以用于自定义拦截解析XML,比如使用了mybatis的定义约束就可以条件判断做一些其他的逻辑。 以下是一个简单地示例,仅仅做一个说明:

代码语言:javascript
复制
public class MyResolver implements EntityResolver {
     public InputSource resolveEntity (String publicId, String systemId)
     {
       if (systemId.equals("http://www.myhost.com/today")) {
                // 包含了自定义的,则自己解析处理
         MyReader reader = new MyReader();
         return new InputSource(reader);
       } else {
                // use the default behaviour
         return null;
       }
     }
}

XMLMapperEntityResolver这个解析器就是判断了下systemId(xml的文档声明)包含org/apache/ibatis/builder/xml/mybatis-3-config.dtd就使用mybatis自定义的InputSource(xml文件配置输入源):

代码语言:javascript
复制
private InputSource getInputSource(String path, String publicId, String systemId) {
    InputSource source = null;
    if (path != null) {
      try {
		// path是mybatis-3-config.dtd的路径
        InputStream in = Resources.getResourceAsStream(path);  
        source = new InputSource(in);
        source.setPublicId(publicId);
        source.setSystemId(systemId);        
      } catch (IOException e) {
        // ignore, null is ok
      }
    }
    return source;
}

所以你应该可以理解通过XMLMapperEntityResolver只是获取了一个InputSource对象(SAX解析器将使用这个InputSource对象来确定如何读取XML输入)。

5.重新回到第【3】步来:构造XPathParser

XMLMapperEntityResolver了解了之后,我们现在回到XPathParser这里,构造XPathParserorg.apache.ibatis.parsing.XPathParser#XPathParser(java.io.InputStream, boolean, java.util.Properties, org.xml.sax.EntityResolver)

构造器:(在XPathParser类的123行处)

代码语言:javascript
复制
// inputStream是我们项目中的mybatis核心配置文件,如:`D:\007\mybatis_demo01\target\classes\SqlMapperConfig.xml`
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
	// 这个构造器会初始化内部的一个属性:javax.xml.xpath.XPath
    commonConstructor(validation, variables, entityResolver);
	// 初始化内部属性:org.w3c.dom.Document,得到一个dom文档
    this.document = createDocument(new InputSource(inputStream));
}

6.重新回到第【2】步来,81行左右:

XPathParser的构造明白后,重新回到第【2】步,看一下XMLConfigBuilder的构造逻辑

代码位置XMLConfigBuilder:org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder(org.apache.ibatis.parsing.XPathParser, java.lang.String, java.util.Properties) 实际调用了85行左右的代码的方法:org.apache.ibatis.builder.xml.XMLConfigBuilder#XMLConfigBuilder(org.apache.ibatis.parsing.XPathParser, java.lang.String, java.util.Properties) 方法如下,这里主要看一下第一行代码也是Configuration的创建:

代码语言:javascript
复制
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    // 设置一些属性
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}

这个方法里面的逻辑我们接着来细看下。

6.1. 第一行super(new Configuration());

第一行代码调用了父类的构造器,即:org.apache.ibatis.builder.BaseBuilder#BaseBuilder

代码语言:javascript
复制
public BaseBuilder(Configuration configuration) {
    this.configuration = configuration;
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}

6.2. Configuration 类是Mybatis的核心配置类,再重要不过了!

我们来看看直接new出来的配置信息类的无参构造器: new Configuration():

代码语言:javascript
复制
public Configuration() {
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

    typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
    typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

    typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
    typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
    typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
    typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
    typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
    typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
    typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

    typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
    typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

    languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
    languageRegistry.register(RawLanguageDriver.class);
}

这里面的都是对应我们在mybatis核心配置文件(mybatis-config.xml)中配置的属性值对应的具体的java类的映射。

Configuration类还定义了很多的属性,这里主要是关于加载的流程分析,不展开讨论这些属性,只在下面代码注释中列举几个说明下:

代码语言:javascript
复制
public class Configuration {

  // 环境配置:<environment id="dev">
  protected Environment environment;

  protected boolean safeRowBoundsEnabled;
  protected boolean safeResultHandlerEnabled = true;
  protected boolean mapUnderscoreToCamelCase;
  protected boolean aggressiveLazyLoading;
  protected boolean multipleResultSetsEnabled = true;
  protected boolean useGeneratedKeys;
  protected boolean useColumnLabel = true;
  protected boolean cacheEnabled = true;
  protected boolean callSettersOnNulls;
  protected boolean useActualParamName = true;
  protected boolean returnInstanceForEmptyRow;

  // 输出日志时的前缀设置
  protected String logPrefix;
  // 指定日志实现类;否则默认按顺序:SLF4J、Apache Commons Logging、Log4j 2、Log4j、JDK logging 查找实现;
  protected Class <? extends Log> logImpl;
  // 虚拟文件系统,会读取接口Mapper.class文件
  protected Class <? extends VFS> vfsImpl;
  // 默认一级缓存为session级别(另一个值是statement级别)
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
  // 在调用这些方法的时候,延迟加载的对象会在调用这些方法之前被加载出来
  protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
  protected Integer defaultStatementTimeout;
  protected Integer defaultFetchSize;
  // 默认的执行器的类型,SIMPLE(默认), REUSE, BATCH
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  // 设置 mapper.xml中表的列(column)和javabean的属性(properties)自动映射的行为
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
  protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;

  protected Properties variables = new Properties();
  protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();

  protected boolean lazyLoadingEnabled = false;
  protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL

  protected String databaseId;
  /**
   * Configuration factory class.
   * Used to create Configuration for loading deserialized unread properties.
   *
   * @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300 (google code)</a>
   */
  protected Class<?> configurationFactory;

  
  // 映射器注册表:使用代理模式;是由MapperProxy代理创建对应的接口Mapper的实例的
  protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
  // 拦截器链,里面list属性interceptors封装了所有的拦截器对象(org.apache.ibatis.plugin.Interceptor)
  protected final InterceptorChain interceptorChain = new InterceptorChain();
  // 类型处理器注册表
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
  // 类型别名注册表
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
  // 语言驱动程序注册表(这些对象一般指org.apache.ibatis.scripting.LanguageDriver的子类)
  // mybatis默认org.apache.ibatis.scripting.xmltags.XMLLanguageDriver类型
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

  protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
  protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
  protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
  protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
  protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");

  protected final Set<String> loadedResources = new HashSet<String>();
  protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");

  protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
  protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
  protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
  protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();

  /*
   * A map holds cache-ref relationship. The key is the namespace that
   * references a cache bound to another namespace and the value is the
   * namespace which the actual cache is bound to.
   */
  protected final Map<String, String> cacheRefMap = new HashMap<String, String>();
}

7.再回到第一步SqlSessionFactoryBuilder#build

截至目前为止,已经构造好了 XMLConfigBuilder 对象了。

我们再回到第一步org.apache.ibatis.session.SqlSessionFactoryBuilder#build(java.io.InputStream, java.lang.String, java.util.Properties),也就是SqlSessionFactoryBuilder类的75行左右。

代码语言:javascript
复制
Configuration对象public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
	  // parser已经拿到了;【截至目前为止,已经构造好了 XMLConfigBuilder  对象了。】
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
	  // 开始追踪这里....[parser.parse()得到Configuration对象]
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
}

7.1 查看org.apache.ibatis.session.SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)方法

build(parser.parse()) 这行代码就是调用这个方法:

代码语言:javascript
复制
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

这个方法传入了一个Configuration对象作为参数,这个参数我们知道是通过parser.parse()得到的。 所以来关注下parser.parse()

7.2 parser.parse()方法

其实就是:org.apache.ibatis.builder.xml.XMLConfigBuilder#parse方法。在XMLConfigBuilder类的94行左右。

代码语言:javascript
复制
public Configuration parse() {
    if (parsed) {// mybatis核心配置文件只允许加载一次
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // 是使用XPath获取根节点:就是config.xml里面的根节点: `<configuration>`。
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}

parser.evalNode("/configuration") 这行代码是使用XPath获取根节点:就是config.xml里面的根节点: <configuration>

7.3 然后再执行这个方法XMLConfigBuilder#parseConfiguration

再来看看这行代码parseConfiguration(parser.evalNode("/configuration"));

org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration,在XMLConfigBuilder类的103行左右。

这个方法就是解析读取mybatis-config.xml文件的各个配置项,并且赋值到configuration里面去(底层是configuration.setXXX方法设置):

代码语言:javascript
复制
private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

这里我们就选取这一行代码 environmentsElement(root.evalNode("environments")); 简单追踪下:

org.apache.ibatis.builder.xml.XMLConfigBuilder#environmentsElement方法如下,你应该可以看到一些熟悉的字眼(数据源的配置信息):

代码语言:javascript
复制
private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
}

就是获取environments节点的信息:

代码语言:javascript
复制
<environments default="dev">
	<environment id="dev">
		<transactionManager type="JDBC"/>
		<dataSource type="POOLED">
			<property name="driver" value="${driver}"/>
			<property name="url" value="${url}"/>
			<property name="username" value="${username}"/>
			<property name="password" value="${password}"/>
		</dataSource>
	</environment>

	<environment id="test">
		<transactionManager type="JDBC"/>
		<dataSource type="POOLED">
			<property name="driver" value="${driver}"/>
			<property name="url" value="${url}"/>
			<property name="username" value="${username}"/>
			<property name="password" value="${password}"/>
		</dataSource>
	</environment>
</environments>

这就是MyBatis核心配置对象Configuration解析加载的主要流程。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Mybatis入门案例
    • 创建maven工程,引入依赖配置项
      • 数据库
        • javabean
          • jdbc.properties
            • mybatis核心配置文件
              • mapper.xml映射文件
                • Mapper.java接口
                  • 测试类
                  • Mybatis加载核心配置文件流程
                    • 1.入口
                      • 2.创建一个【XMLConfigBuilder】解析器类
                        • 3.【XPathParser】解析器的构造器
                          • 4.【XMLMapperEntityResolver】实体解析器
                            • 5.重新回到第【3】步来:构造XPathParser
                              • 6.重新回到第【2】步来,81行左右:
                                • 6.1. 第一行super(new Configuration());
                                • 6.2. Configuration 类是Mybatis的核心配置类,再重要不过了!
                              • 7.再回到第一步SqlSessionFactoryBuilder#build
                                • 7.1 查看org.apache.ibatis.session.SqlSessionFactoryBuilder#build(org.apache.ibatis.session.Configuration)方法
                                • 7.2 parser.parse()方法
                                • 7.3 然后再执行这个方法XMLConfigBuilder#parseConfiguration
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档