mybatis源码---初始化configuration

我们的调试环境:

调试代码:

public class MyaaTest {
    public static void main(String[]args) {
        String resource = "config.xml";
        try {
            //1.读取配置文件
            InputStream in= Resources.getResourceAsStream(resource);
            SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(in); //解析配置文件
            //2. 打开连接
            SqlSession session=sessionFactory.openSession();
            String statement="com.it.dao.UserMapper.selectById";
            //3.方法调用
            User user=session.selectOne(statement);

            System.out.println(user.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

第一步:进入Resources 类中,这个类对于xml来说,很熟悉了

public static InputStream getResourceAsStream(String resource) throws IOException {
  return getResourceAsStream(null, resource);
}
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
  InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader); //【入】
  if (in == null) { //五个classloader 都失败了,那么就只能报错了!
    throw new IOException("Could not find resource " + resource);
  }
  return in;
}

第二步:进入ClassLoaderWrapper 很明显这是类加载器的包装类

看一下成员:

public class ClassLoaderWrapper {

  ClassLoader defaultClassLoader;
  ClassLoader systemClassLoader;
  ClassLoaderWrapper() {
      systemClassLoader = ClassLoader.getSystemClassLoader();
  }
...
}

我们使用的是静态方法,这个里面有两个类加载器(我们之前在学习jvm的时候,学习过classLoader,它的主要功能就是负责在文件系统中,找到class文件,加载到jvm中),我们这里希望找到的是xml。

注意classLoader为null

public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
  return getResourceAsStream(resource, getClassLoaders(classLoader)); //注入了五个classloader
}

看返回的第二个参数:

ClassLoader[] getClassLoaders(ClassLoader classLoader) {
  return new ClassLoader[]{
      classLoader,  //null
      defaultClassLoader, //null
      Thread.currentThread().getContextClassLoader(),
      getClass().getClassLoader(),
      systemClassLoader};
}

返回了五个类加载器,第一个,第二个是Null,默认的类加载器,没有发现实例化的过程。

InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
  for (ClassLoader cl : classLoader) { //遍历Classloader
    if (null != cl) {
      InputStream returnValue = cl.getResourceAsStream(resource); //尝试进行加载
      if (null == returnValue) { //查找失败,再次尝试
        returnValue = cl.getResourceAsStream("/" + resource);
      }
      if (null != returnValue) { return returnValue; } //加载成功就推出,返回流
    }
  }
  return null;
}

我们的配置文件,就在根目录下,第三个类加载器 找到了我们的xml文件

 

第三步:进入SqlSessionFactoryBuilder 类中

该类的结构,分为两部分(还有一个列外)

一个小组分为三个build和一个dobuild(), 第一组传入的主要是Reader,第二组传入的是inputStream,我们自然走第二组

public SqlSessionFactory build(InputStream inputStream) {
  return build(inputStream, null, null);
}

这些重载就是传入参数不同而已,但是为了扩展,又不得不这样做(就如同go里面可以返回多个参数一个道理)

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    return build(parser.parse());
}

 

第四步:进入XMLConfigBuilder类中

public class XMLConfigBuilder extends BaseBuilder {
  private boolean parsed; //是否已解析,XPath解析器,环境
  private XPathParser parser;
  private String environment;
}

该类的[构造函数]结构和SqlSessionFactoryBuilder一样,通用分为两组reader+stream,最后流入builder方法中进行执行

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
  this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}

它使用stream,构建了XPathParser类,传入下一个终构造函数中

XPath解析器:使用的是jdk的包,封装了一下,使用起来更方便

public class XPathParser {

  private Document document;
  private boolean validation;
  private EntityResolver entityResolver;
  private Properties variables;
  private XPath xpath;
}

终构造函数,将各个属性都配置好了,

//上面6个,封装出了parser,流入这里
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
  super(new Configuration());     ///首先调用父类初始化Configuration
  ErrorContext.instance().resource("SQL Mapper Configuration"); //错误上下文设置成SQL Mapper Configuration(XML文件配置),以便后面出错了报错用吧
  //将Properties全部设置到Configuration里面去
  this.configuration.setVariables(props);
  this.parsed = false;
  this.environment = environment;
  this.parser = parser;
}

准备好了,开始解析:parse()

给一个待解析的模板xml

<?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>
 <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="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
public Configuration parse() {
//如果已经解析过了,报错
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
//解析配置
private void parseConfiguration(XNode root) {
  try {
    //分步骤解析
    //issue #117 read properties first
    //1.properties
    propertiesElement(root.evalNode("properties"));
    //2.类型别名
    typeAliasesElement(root.evalNode("typeAliases"));
    //3.插件
    pluginElement(root.evalNode("plugins"));
    //4.对象工厂
    objectFactoryElement(root.evalNode("objectFactory"));
    //5.对象包装工厂
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    //6.设置
    settingsElement(root.evalNode("settings"));
    // read it after objectFactory and objectWrapperFactory issue #631
    //7.环境
    environmentsElement(root.evalNode("environments"));
    //8.databaseIdProvider
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    //9.类型处理器
    typeHandlerElement(root.evalNode("typeHandlers"));
    //10.映射器
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  }
}

查看这个类的父类:

public abstract class BaseBuilder {
  //需要配置,类型别名注册,类型处理器注册3个东西
  protected final Configuration configuration; //保存解析的结果 
  protected final TypeAliasRegistry typeAliasRegistry;
  protected final TypeHandlerRegistry typeHandlerRegistry;
}

返回这个configuration结果就可以了。

 

将该结果进行封装,方便使用。

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }
}

对于这个具体解析parse()内容很多,我们下一节再讲

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值