关于mybaitis
mybatis启动流程
1、首先来看看最简单的mybatis项目启动过程
public static void mybatisTest() throws IOException {
String resource = "mybatis/mybatis-config.xml";
//配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = null;
try {
//开启一个session
sqlSession = sqlSessionFactory.openSession();
//获取mapper
JobConfigDao jobConfigDao = sqlSession.getMapper(JobConfigDao.class);
//查询数据
List<JobConfig> jobConfigList = jobConfigDao.listConfig();
System.out.println(jobConfigList);
} finally {
if (sqlSession != null)
sqlSession.close();
}
}
这个过程主要是SqlSessionFactory 的创建,先获取配置信息,然后通过SqlSessionFactoryBuilder来创建SqlSessionFactory 。
build方法的核心代码是:
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
可以看到mybatis是通过XMLConfigBuilder来解析配置文件的。来看看XMLConfigBuilder的parse方法:
public Configuration parse() {
//XMLConfigBuilder中有一个boolean类型parsed,来标记是否解析过配置文件,解析过之后就设置为true,防止同样的配置被重复解析
if (this.parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
} else {
this.parsed = true;
// 解析configuration节点下的配置
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
private void parseConfiguration(XNode root) {
try {
this.propertiesElement(root.evalNode("properties"));
Properties settings = this.settingsAsProperties(root.evalNode("settings"));
this.loadCustomVfs(settings);
this.typeAliasesElement(root.evalNode("typeAliases"));
this.pluginElement(root.evalNode("plugins"));
this.objectFactoryElement(root.evalNode("objectFactory"));
this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
this.settingsElement(settings);
this.environmentsElement(root.evalNode("environments"));
this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
this.typeHandlerElement(root.evalNode("typeHandlers"));
// 解析mapper
this.mapperElement(root.evalNode("mappers"));
} catch (Exception var3) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
}
}
可以看到,在parseConfiguration方法中会将mybatis-config.xml配置下的各种属性获取出来一一解析,并映射到相关的属性上面去。
mybatis定义的接口,怎么找到实现的?
通过上面的启动过程,已经知道mybatis是通过XMLConfigBuilder来解析配置文件的,具体解析是在parseConfiguration方法的中,获取到mappers配置节点,最后一行this.mapperElement(root.evalNode("mappers"))将节点信息转交给XMLMapperBuilder来完成对mapper的解析。
来看看XMLMapperBuilder的parse方法:
public void parse() {
if (!this.configuration.isResourceLoaded(this.resource)) {
this.configurationElement(this.parser.evalNode("/mapper"));
this.configuration.addLoadedResource(this.resource);
//通过命名空间绑定mapper
this.bindMapperForNamespace();
}
this.parsePendingResultMaps();
this.parsePendingCacheRefs();
this.parsePendingStatements();
}
因为这里的重点是想知道定义的接口是怎么实现的,所以直接来看看bindMapperForNamespace方法对如何来实现mapper的绑定:
private void bindMapperForNamespace() {
String namespace = this.builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class boundType = null;
try {
//通过反射获取类类型
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException var4) {
;
}
//如果当前类还没有绑定到配置的缓存中
if (boundType != null && !this.configuration.hasMapper(boundType)) {
this.configuration.addLoadedResource("namespace:" + namespace);
//通过mybatis的Configuration将mapper注册到MapperRegistry
this.configuration.addMapper(boundType);
}
}
}
来看看MapperRegistry 的addMapper:
public <T> void addMapper(Class<T> type) {
this.mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {//先判断是否为接口
if (this.hasMapper(type)) {//如果已经注册,抛出异常
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//创建一个代理MapperProxyFactory 并将该mapper缓存到内存的Map中去
this.knownMappers.put(type, new MapperProxyFactory(type));
//绑定注解
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
this.knownMappers.remove(type);
}
}
}
}
通过对上面源码的跟踪分析,终于知道,mybatis通过MapperProxyFactory为每个接口都提供了一个代理实现,然后通过MapperRegistry将mapper注册到容器中的。
那么在使用的时候又是如何来获取这个mapper的呢?
答案是:反射加上代理
首先通过SqlSession的getMapper方法,mybatis为SqlSession提供了一个默认的实现DefaultSqlSession,DefaultSqlSession的内部属性如下:
//Configuration配置
private final Configuration configuration;
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
DefaultSqlSession获取配置,然后配置中获取MapperRegistry,从MapperRegistry中获取到mapper代理工厂,再通过MapperProxyFactory的newInstance来创建mapper代理类MapperProxy
总结:对于Mybatis,记住几个关键的处理类:SqlSessionFactoryBuilder创建SqlSessionFactory,SqlSessionFactory中开启一个SqlSession,通过sqlSession来执行用户操作;RegisterMapper将mapper注册到容器中,通过MapperProxyFactory来创建mapper代理,mapper代理最终是通过jdk反射包中Proxy代理类来创建的。
启动时创建的SqlSessionFactory是DefaultSqlSessionFactory,DefaultSqlSessionFactory中拥有属性Configuration,Configuration是通过XMLConfigBuilder从配置文件中解析出来的各种配置信息,Configuration中有MapperRegistry,MapperRegistry中用一个final类型的Map存储了用户定义Mapper代理实现工厂MapperProxyFactory,Mapper代理实现是MapperProxy。
关于mybaitis的更多相关文章
- java web后台开发SSM框架(Spring+SpringMVC+MyBaitis)搭建与优化
一.ssm框架搭建 1.1创建项目 新建项目后规划好各层的包. 1.2导入包 搭建SSM框架所需包百度云链接:http://pan.baidu.com/s/1cvKjL0 1.3整合spring与my ...
- Mybaitis配置总结
在mybatis-config.xml中配置分页插件,插件配置必须放在mapper前面 <plugins> <plugin interceptor="com.rrtong. ...
- 缓存策略 半自动化就是mybaitis只支持数据库查出的数据映射到pojo类上,而实体到数据库的映射需要自己编写sql语句实现,相较于hibernate这种完全自动化的框架我更喜欢mybatis
springboot入门(三)-- springboot集成mybatis及mybatis generator工具使用 - FoolFox - CSDN博客 https://blog.csdn.net ...
- spring mvc整合mybaitis和log4j
在上一篇博客中,我介绍了在mac os上用idea搭建spring mvc的maven工程,但是一个完整的项目肯定需要数据库和日志管理,下面我就介绍下spring mvc整合mybatis和log4j ...
- mybaitis的延迟加载
概念:延迟加载:用到的时候才加载 因为我们在多表查询是,效率不如单表快,多个单表查询,然后使用懒加载,完成 多表关联查询 什么情况下使用懒加载 mybaitis中的表关系是一对一或者一对多的时候 我们 ...
- springboot实现mybaitis逆向工程
springboot实现mybaitis逆向工程 首先引入依赖,一共需要两个依赖(一个是mybaits依赖,一个是mybatis逆向工程插件) <dependency> <group ...
- mybaitis uuid插入和定义返回类型
- Spring、SpringMVC、Mybaitis框架配置
给大家推荐2个网址,介绍的非常详细 SSM环境搭建 http://blog.csdn.net/zhshulin/article/details/37956105 SSM代码生成工具介绍 http:// ...
- mybaitis配置信息
在配置mybatis当中,jdbcType的名称要大写,时间类型DATE只能传入年月日,要想传入时分秒,应该使用TIMESTAMP http://www.blogjava.net/hello-yun/ ...
- mybaitis动态sql利用bind标签代替%拼接完成模糊查询
Oracle中使用bind的写法 <select id="selectUser" resultType="user" parameterType=&quo ...
随机推荐
- Apache Hadoop集群离线安装部署(二)——Spark-2.1.0 on Yarn安装
Apache Hadoop集群离线安装部署(一)——Hadoop(HDFS.YARN.MR)安装:http://www.cnblogs.com/pojishou/p/6366542.html Apac ...
- 换了SSD发现plank也好了
我的Dock用的是plank,很简单很好用.为什么不用Docky还有其他什么玩意儿呢?plank很简单很好用,资源占用很少,可以智能隐藏,you nearly can't feel it but yo ...
- linux常用命令记录(一)
文件搜索命令 grep在文件中查找字符并输出 grep 字符或字符串 文件目录 grep pub /teach/.txt -c 字符出现总行数 grep .txt -n 行号 grep .txt -i ...
- 分组取前N记录(转)
版权声明:本文为博主原创文章,未经博主允许不得转载. 经常看到问题,如何取出每组的前N条记录.方便大家参考于是便把常见的几种解法列出于下. 问题:有表 如下,要求取出各班前两名(允许并列第二)Tabl ...
- PHP-删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...
- vue中key的作用
1.v-if中用key管理可复用的元素 Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染.这么做,除了使 Vue 变得非常快之外,还有一些有用的好处.例如,如果你允许用户在不同的 ...
- eclipse配置spring4.0环境详细教程
最近几天学习spring框架,在环境搭建过程中遇到了不少问题,网上找了不少资料都不是特别好,所以自己重新记录一下. 准备: 1.Eclipse下载,进官网,这里直接给链接了https://www.ec ...
- laravel将数组转换成集合
$myArray = collect($this -> menuPermissionTypes); //$this -> menuPermissionTypes是数组! dd($myArr ...
- Python改变当前工作目录
import os print(os.getcwd()) # 打印当前工作目录 os.chdir('/Users/<username>/Desktop/') # 将当前工作目录改变为`/U ...
- Java高并发网络编程(四)Netty
在网络应用开发的过程中,直接使用JDK提供的NIO的API,比较繁琐,而且想要进行性能提升,还需要结合多线程技术. 由于网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以在开源社区中,涌 ...