Mybatis的配置文件主要有二個,分析爲總的配置文件和Mapper的配置文件
總的配置文件的主要配置如下
<?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"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${mybaties.driver}"/>
<property name="url" value="${mybaties.url}"/>
<property name="username" value="${mybaties.username}"/>
<property name="password" value="${mybaties.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
db.properties的配置內容如下
mybaties.driver=com.mysql.jdbc.Driver
mybaties.url=jdbc:mysql://localhost:3306/crm
mybaties.username="root"
mybaties.password=123456
Mapper的配置文件的內容如下
<?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">
<mapper namespace="com.hailong.user">
<resultMap type="com.hailong.mybaties.User" id="detailUserResultMap">
<constructor>
<idArg column="user_id" javaType="String"/>
<arg column="user_name"/>
</constructor>
<result property="password" column="user_pwd" />
<result property="type" column="user_type" javaType="com.hailong.mybaties.UserType"/>
<result property="svcnum" column="svc_num" />
<association property="cust" javaType="com.hailong.mybaties.Cust">
<id property="id" column="cust_id"/>
<result property="custname" column="cust_name"/>
<result property="certNo" column="cert_no"/>
</association>
<collection property="accts" column="" ofType="com.hailong.mybaties.Acct">
<id property="id" column="acct_id" />
<result property="payName" column="pay_name"/>
<result property="bankNo" column="bank_no"/>
</collection>
</resultMap>
<select id="selectUserDetail" resultMap="detailUserResultMap">
select id,user_name,user_type,cust_id from user a where a.user_id=#{userId}
</select>
</mapper>
Mybaties的測試代碼如下
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSesstionFactoryTest
{
public static void main(String[] args) throws Exception
{
String resouce="mybatis-config.xml";
//這個resource本身就會到類路徑下去找這個配置文件
InputStream is=Resources.getResourceAsStream(resouce);
//這裏是正式開始讀取配置文件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is); //1
//進行操作
//SqlSession sqlSession=sqlSessionFactory.openSession();
System.out.println(sqlSessionFactory.getConfiguration());
}
}
new SqlSessionFactoryBuilder()什麼內容都沒有做,只是單單創建了一個SqlSessionFactoryBuilder對象,在這個對象的內部提供了大量的bulider方法,主要是用來創建這個SqlSessionFactory對象的,同時這個SqlSessionFactory對象的創建主要是使用了創建類設計模式的Builder設計模式,主要是用來構造一個複雜的對象,其實在Mybatis當中很多類對象的創建使用了Builder設計模式,下面就是這個就是創建我們的SqlSessionFactory對象所有方式。
其實在創建這個SqlSessionFactory對象的同時,也就是解析Mybatis的二個配置文件的過程封裝到我們的Configration對象當中,如下圖所示
修改測試代碼如下
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SqlSesstionFactoryTest
{
public static void main(String[] args) throws Exception
{
String resouce="mybatis-config.xml";
//這個resource本身就會到類路徑下去找這個配置文件
InputStream is=Resources.getResourceAsStream(resouce);
//這裏是正式開始讀取配置文件
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
//得到解析mybatis的二個配置文件的所有的內容
Configuration config=sqlSessionFactory.getConfiguration();
System.out.println(config);
//進行操作
SqlSession sqlSession=sqlSessionFactory.openSession();
System.out.println(sqlSessionFactory.getConfiguration());
}
}
結果如下:這個datasources當中的內容和我們的db.properties的內容一樣,MappedStatement中的內容和我們的userMapper.xml文件中的內容一樣,也就是說創建這個SqlSessionFactory對象的同時解析Mybatis的二個配置文件的過程封裝到我們的Configration對象當中
下面開始進行Debuger我們的Mybatis源碼
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {//主要是創建XMLConfigBuilder對象來解析mybatis的核心配置文件(mybatisconfig.xml)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());//1 進行看完後發現 parser.parse()返回的是一個Configration對象,也就是說他把//mybatisconfig.xml已經封裝到了Configration對象當中了 } 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. } } }
跳轉到parser.parse()進行解析我們的mybatisconfig.xml當中的內容,這個文件當中的所有內容已經全部封裝到了InputStream流當中了
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true; //表示已經用過了個XMLConfigBuilder解析過這個配置文件,也說明了這個配置文件在開啓時只解析一次
//下面就是解析這個配置文件的具體過程 /configuration是我們的mybatis配置文件的根標籤<configuration> ,
//同時這個parser.evalNode("/configration")解析mybatiesconfig.xml文件,然後返回這個配置文件的根標籤元素
parseConfiguration(parser.evalNode("/configuration"));//parseConfiguration(Node root) /內封裝的是解析根標籤下的子標籤的內容
return configuration;
}
這個evalNode(string express)是根據配置文件當中標籤的名字來獲取相應的標籤結點
public XNode evalNode(String expression) {
return evalNode(document, expression);
}
//XNode返回的是我們的根結點 configration
public XNode evalNode(Object root, String expression) {
Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
if (node == null) {
return null;
}
return new XNode(this, node, variables);
}
對應我們的mybatisconfig.xml的根標籤configration,同理其他的結點是在這個根結點的基礎下進行解析(下面會講到)
接下來就是在這個根標籤的基礎上進行解析這個配置文件了,具體細節來看這個parseConfiguration(XNode root)方法,也就是解析這個配置文件當中的子內容
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
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);
}
}
先來看一下這個XMLConfigBulider的所有解析mybatiesconfig.xml的方法
第一個parse()方法獲取根標籤
第二個parseConfiguration(XNode)是解析mybatisconfig.xml的核心所有,在這個方法當中調用了所有的XMLConfigBuilder的解析方法
第三個propertiesElement(XNode)是解析我們的properties屬性,同時封裝到Confuration當中
這裏有一個知識點就是我們的Properties文件的resource和url屬性只能配置一個,不能同時配置二個
下面看一下getResourceAsProperties()的代碼如下
/*
* Returns a resource on the classpath as a Properties object
*
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Properties getResourceAsProperties(String resource) throws IOException {
Properties props = new Properties();
InputStream in = getResourceAsStream(resource);
props.load(in);
in.close();
return props;
}