Mybatis源码篇(二)—— properties、environments标签解析

配置文件中的配置信息以及测试类:

首先在mybatis配置文件中添加properties和enviroments配置,并引入外部配置db.properties

<?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="db.properties">
        <property name="userName" value="root"/>
        <property name="password" value="123456"/>
    </properties>

    <environments default="development">
        <environment id="development">
            <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>

    <mappers>
        <mapper resource="cn/zsm/mybatis/man/ManMapper.xml"/>
        <mapper resource="cn/zsm/mybatis/student/StudentMapper.xml"/>
    </mappers>

</configuration>

db.properties中配置的属性

userName=root
password=123456
url=jdbc:mysql://localhost:3306/zsmtest
driver=com.mysql.jdbc.Driver

然后我们启动测试类,进入XMLConfigBuilder 的parseConfiguration(XNode root)方法, 逐步观察mybatis是如何解析这两个标签的:

    @Test
    public void test3() throws IOException {
        StudentMapper mapper = getSqlSession().getMapper(StudentMapper.class);
        List<Student> students = mapper.selectStudents();
        for (Student student : students){
            System.out.println(student.toString());
        }
    }

    private SqlSession getSqlSession() throws IOException {
        String resource = "configuration.xml";
        InputStream stream = Resources.getResourceAsStream(resource);
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(stream);
        SqlSession sqlSession = build.openSession();
        return sqlSession;
    }

XMLConfigBuilder :parseConfiguration(XNode root)方法

    public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

    private void parseConfiguration(XNode root) {
        try {
            this.propertiesElement(root.evalNode("properties"));
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
            this.loadCustomLogImpl(settings);
            this.typeAliasesElement(root.evalNode("typeAliases"));
            this.pluginElement(root.evalNode("plugins"));
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
            this.settingsElement(settings);
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }
  • this.propertiesElement(root.evalNode("properties"));解析properties标签
  • this.environmentsElement(root.evalNode("environments"));解析environments标签

propertiesElement:

    private void propertiesElement(XNode context) throws Exception {
        if (context != null) {
            Properties defaults = context.getChildrenAsProperties();
            String resource = context.getStringAttribute("resource");
            String url = context.getStringAttribute("url");
            if (resource != null && url != null) {
                throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
            }

            if (resource != null) {
                defaults.putAll(Resources.getResourceAsProperties(resource));
            } else if (url != null) {
                defaults.putAll(Resources.getUrlAsProperties(url));
            }

            Properties vars = this.configuration.getVariables();
            if (vars != null) {
                defaults.putAll(vars);
            }

            this.parser.setVariables(defaults);
            this.configuration.setVariables(defaults);
        }

    }

1、获取properties标签下的信息和内部定义property信息:

2、获取resource属性和url属性信息,且如果两个属性最多只能有一个属性为空

3、读书resource或url指向的配置文件的配置信息。主要这里读取配置信息并存储时,将信息存储在default中:

而这时defaults中已经存储了解析property标签时的信息,如果引入的配置文件中含有与property中相同的key值,则会将原来的值覆盖。这里也可以看出配置文件中属性读取的顺序和属性取值的优先级。

这时我们再看deaults中的值:

4、到这里properties中的属性信息已经读取完毕,读取的信息复制给variables属性。

environmentsElement:

    private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (this.environment == null) {
                this.environment = context.getStringAttribute("default");
            }

            Iterator var2 = context.getChildren().iterator();

            while(var2.hasNext()) {
                XNode child = (XNode)var2.next();
                //解析id属性值
                String id = child.getStringAttribute("id");
                //如果当前enviroment的id等于默认的id,则进行解析
                if (this.isSpecifiedEnvironment(id)) {
                    TransactionFactory txFactory = this.transactionManagerElement(child.evalNode("transactionManager"));
                    DataSourceFactory dsFactory = this.dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
                    Builder environmentBuilder = (new Builder(id)).transactionFactory(txFactory).dataSource(dataSource);
                    this.configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }

    }

1、开始解析enviroments标签,如果当前enciroment属性为空,则获取default属性指定的enviromentID

2、获取enviroments标签下所有子标签enviroment,并遍历。由于我们这里只配置了一个enviroment,所以context.getChildren()也只有一个元素。

    public List<XNode> getChildren() {
        List<XNode> children = new ArrayList();
        NodeList nodeList = this.node.getChildNodes();
        if (nodeList != null) {
            int i = 0;
            for(int n = nodeList.getLength(); i < n; ++i) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == 1) {
                    children.add(new XNode(this.xpathParser, node, this.variables));
                }
            }
        }
        return children;
    }

3、解析enviroment标签下,其它标签的信息:id、transactionManager、datasource,并获取TransactionFactory事物工厂和DataSourceFactory数据库链接工厂。

TransactionFactory:

public interface TransactionFactory {
    void setProperties(Properties var1);

    Transaction newTransaction(Connection var1);

    Transaction newTransaction(DataSource var1, TransactionIsolationLevel var2, boolean var3);
}

DataSourceFactory:

public interface DataSourceFactory {
    void setProperties(Properties var1);

    DataSource getDataSource();
}

两个工厂的信息如下图:

我们可以看到,datasource中有一些连接池的配置信息,但是我们并没有配置连接池。这是mybatis中默认配置的连接池信息。

会议一下我们使用JDBC链接数据库的时候,需要用到Connection类,而这里也是链接数据库,其中DataSource就是java.sql包下的类:

package javax.sql;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Wrapper;

public interface DataSource  extends CommonDataSource, Wrapper {

  Connection getConnection() throws SQLException;

  Connection getConnection(String username, String password)
    throws SQLException;
}

到这里,数据库链接的配置读取和设置完毕。也就是我们已经可以与数据库建立连接了。

发布了74 篇原创文章 · 获赞 19 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/zhoushimiao1990/article/details/100153793
今日推荐