mybatis源码学习(三)

本文详细解析了MyBatis框架中资源加载的过程,包括如何读取全局配置文件myBatis-config.xml,通过SqlSessionFactoryBuilder生成SqlSessionFactory,以及创建SqlSession进行数据库操作。深入探讨了XMLConfigBuilder和XPathParser在配置解析中的作用。
mybatis资源加载

上一篇文章介绍了搭建mybatis源码分析的工程,在测试工程里面看到,在进行数据库操作前,必须先加载mybatis的相关资源。
在这里插入图片描述
在start方法里面,首先通过Resources.getResourceAsStream(“myBatis-config.xml”)方法,读取mybatis的全局配置,接着通过SqlSessionFactoryBuilder().build(inputStream)方法生成一个SqlSessionFactory,最后SqlSessionFactory调用openSession()方法生成SqlSession。

public void start(){
   try{
    	//读取myBatis全局配置文件信息把数据源、mapper映射文件等配置信息读取出来
        InputStream inputStream = Resources.getResourceAsStream("myBatis-config.xml");
        //通过SqlSessionFactoryBuilder生成SqlSessionFactory
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
        //生成SqlSession
        session=factory.openSession();
    }catch(Exception exception){
        exception.printStackTrace();
    }
}
  1. SqlSessionFactoryBuilder
    在SqlSessionFactoryBuilder里面主要有3种方式构造SqlSessionFactory,第一种是通过InputStream构造,第二种是通过Reader构造,第三种是直接传入org.apache.ibatis.session.Configuration,三种构造方式没有本质上的区别,前面两种是通过类似配置文件的方式构造,第三种方式是先构造了配置类,然后通过配置类构造SqlSessionFactory,前面两种方法最后面在真正执行。
public class SqlSessionFactoryBuilder {
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }
  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

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

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

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

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } 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.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
  1. XMLConfigBuilder,在SqlSessionFactoryBuilder中,首先创建XMLConfigBuilder对象,这个对象是专门解析MyBatis配置类用的,构造函数如下:
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
	this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}

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

从上面可以看出,其实不管是传入的是Reader还是传入的是InputStream,两者都是用来创建XPathParser对象的,因此正如上面说的,传入两者没什么区别。刚才的测试类的start方法中,创建SqlSessionFactoryBuilder的时候,在执行build方法的时候,只传进去了InputStream因此这里的environment和props两个参数都是空

SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

在创建XMLConfigBuilder的时候,先创建XPathParser对象

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

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
  super(new Configuration());
  ErrorContext.instance().resource("SQL Mapper Configuration");
  this.configuration.setVariables(props);
  this.parsed = false;
  this.environment = environment;
  this.parser = parser;
}

在创建XPathParser的时候,传入4个参数配置文件的流,true,props以及新创建的XMLMapperEntityResolver对象

  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(inputStream));
  }
  private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
    this.validation = validation;
    this.entityResolver = entityResolver;
    this.variables = variables;
    XPathFactory factory = XPathFactory.newInstance();
    this.xpath = factory.newXPath();
  }
  private Document createDocument(InputSource inputSource) {
    // important: this must only be called AFTER common constructor
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setValidating(validation);

      factory.setNamespaceAware(false);
      factory.setIgnoringComments(true);
      factory.setIgnoringElementContentWhitespace(false);
      factory.setCoalescing(false);
      factory.setExpandEntityReferences(true);

      DocumentBuilder builder = factory.newDocumentBuilder();
      builder.setEntityResolver(entityResolver);
      builder.setErrorHandler(new ErrorHandler() {
        @Override
        public void error(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void warning(SAXParseException exception) throws SAXException {
        }
      });
      return builder.parse(inputSource);
    } catch (Exception e) {
      throw new BuilderException("Error creating document instance.  Cause: " + e, e);
    }
  }

从上面的代码可以看到,在SqlSessionFactoryBuilder创建XMLConfigBuilder的时候,只是把配置文件初始化到对象里面,此时还没对配置文件进行解析。接着,执行return build(parser.parse());代码对配置文件进行解析。
在parser.parse()方法中,即调用的是XMLConfigBuilder的parse()方法

 public Configuration parse() {
  if (parsed) {
     throw new BuilderException("Each XMLConfigBuilder can only be used once.");
   }
   parsed = true;
   parseConfiguration(parser.evalNode("/configuration"));
   return configuration;
 }

在parse方法里面通过调用parseConfiguration(parser.evalNode("/configuration"))方法初始化配置信息,这里传入的参数是配置文件里面configuration这个节点的信息。

源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值