Mybaties源码分析

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







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值