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;
}