Configuration information in configuration files and test classes:
First, add properties and enviroments configuration to mybatis configuration file, and introduce external configuration 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>
Properties configured in db.properties
userName=root password=123456 url=jdbc:mysql://localhost:3306/zsmtest driver=com.mysql.jdbc.Driver
Then we start the test class and enter the parseConfiguration(XNode root) method of the XMLConfigBuilder to gradually observe how mybatis parses the two tags:
@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) method
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. properties Element (root. evalNode ("properties"); parses properties Tags
- this.environmentsElement(root.evalNode("environments"); parses environment Tags
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. Get the information under the properties label and the internal definition property information:
2. Get the resource attribute and url attribute information, and if at most one of the two attributes is empty
3. Read the configuration information of the configuration file pointed by resource or url. When reading configuration information and storing it here, the information is stored in default:
At this time, defaults already stores the information when parsing the property tag. If the imported configuration file contains the same key value as in property, the original value will be overwritten. Here you can also see the order in which attributes are read and the priority in which attributes are valued in the configuration file.
Now let's look at the values in deaults:
4. Attribute information in properties has been read here, and the read information is copied to variable attributes.
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(); //Parsing id attribute values String id = child.getStringAttribute("id"); //If the ID of the current enviroment equals the default id, parse 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. Start parsing the enviroments tag. If the current enciroment attribute is empty, get the enviromentID specified by the default attribute.
2. Get all sub-labels under the enviroments label and traverse them. Since we configure only one enviroment here, context.getChildren() also has only one element.
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. Parse the information of other tags under the enviroment tag: id, transactionManager, datasource, and get the TransactionFactory Things Factory and DataSourceFactory Database Link Factory.
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(); }
The information of the two factories is as follows:
We can see that there are some configuration information for connection pools in data source, but we do not configure connection pools. This is the connection pool information configured by default in mybatis.
When we use JDBC to link databases, we need to use the Connection class, which is also the linked database, where DataSource is the class under the java.sql package:
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; }
Here, the configuration of the database link is read and set up. That is to say, we can already establish a connection with the database.