Mybatis原理mybatis源码原理主要是分为三个部分 初始化、创建会话、语句执行
一、初始化1.读取配置文件mybatis-config.xml 。
2.解析mApper.xml文件 。
3.最后将mapper.xml中的sql语句全部保存到了Map mappedStatements中(mappedStatements的key:namespace+sqlId,value:MappedStatement
mappedStatements还会保存namespace和代理工厂的映射关系 , 存入到knownMappers.put(type, newMapperProxyFactory<>(type));) 。
源码实现public void prepare() throws IOException {//加载mybatis-config.xml配置文件String resource = "mybatis-config.xml";//将mybatis配置文件转换成流的形式InputStream inputStream = Resources.getResourceAsStream(resource);//new一个SqlSessionFactoryBuilder , 然后将流传进去 , 是为了得到一个 sqlSessionFactory//这里使用到了建造者模式SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}
我们通过上面的build开始阅读我们mybatis的源码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {// 开始解析 mybatis-config.xml , 并且创建了 Configuration 对象//Configuration 对象是对应mybatis-config.xml中的一些配置的XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);// 解析XML , 最终返回一个 DefaultSqlSessionFactory >>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.}}}
解析mybatis-config.xml 从 configuration 开始解析 , 也就是我们xml中的最上层配置开始解析
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");}parsed = true;parseConfiguration(parser.evalNode("/configuration"));return configuration;}
是一层一层对mybatis-config.xml进行解析 , 并将所有的标签都放到了Configuration中 , 我们可以看到一下代码中的参数
private void parseConfiguration(XNode root) {try {// 对于全局配置文件各种标签的解析,将标签放到Configuration中propertiesElement(root.evalNode("properties"));// 解析 settings 标签Properties settings = settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);loadCustomLogImpl(settings);// 类型别名typeAliasesElement(root.evalNode("typeAliases"));// 插件pluginElement(root.evalNode("plugins"));// 用于创建对象objectFactoryElement(root.evalNode("objectFactory"));// 用于对对象进行加工objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));// 反射工具箱reflectorFactoryElement(root.evalNode("reflectorFactory"));// settings 子标签赋值 , 默认值就是在这里提供的 >>settingsElement(settings);// 创建数据源environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));// 解析引用的Mapper映射器 这个是最重要的操作mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}
我们来看一下最重要的方法都做了哪些操作
private void mapperElement(XNode parent) throws Exception {if (parent != null) {for (XNode child : parent.getChildren()) {// 不同的定义方式的扫描 , 最终都是调用 addMapper()方法(添加到 MapperRegistry) 。这个方法和 getMapper() 对应// <package name="com.xinyu.demo"/>包含这样的标签才会走if操作//else 走的是 <mapper resource="BlogMapper.xml"/>这样的标签if ("package".equals(child.getName())) {String mapperPackage = child.getStringAttribute("name");configuration.addMappers(mapperPackage);} else {String resource = child.getStringAttribute("resource");String url = child.getStringAttribute("url");String mapperClass = child.getStringAttribute("class");if (resource != null && url == null && mapperClass == null) {// resource相对路径ErrorContext.instance().resource(resource);InputStream inputStream = Resources.getResourceAsStream(resource);XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());// 解析 Mapper.xml , 详情看下方代码块mapperParser.parse();} else if (resource == null && url != null && mapperClass == null) {// url 绝对路径ErrorContext.instance().resource(url);InputStream inputStream = Resources.getUrlAsStream(url);XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());mapperParser.parse();} else if (resource == null && url == null && mapperClass != null) {// class单个接口Class<?> mapperInterface = Resources.classForName(mapperClass);configuration.addMapper(mapperInterface);} else {throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");}}}}}
推荐阅读
- 根据交换机的工作原理可知,交换机可以多个端口对之间的数据传输
- 路由交换技术—VLAN原理及配置
- Linux容器技术原理和使用
- 一文了解神经网络工作原理
- 搜索引擎抓取信息的原理
- SQL注入攻击的原理
- Redis详解:原理和机制
- Spring Boot启动原理解析
- C++ 一篇搞懂多态的实现原理
- 荧光灯如何选购 荧光灯工作原理