@

相关文章推荐
mybatis 缓存的使用, 看这篇就够了
mybatis源码-解析配置文件(四)之配置文件Mapper解析

1. 简介

本文章主要讲解的是, xxxMapper.xml 文件中, cache 节点的源码。

2. 解析

XMLMapperBuilder.cacheElement() 方法主要负责解析 <cache>

  private void cacheElement(XNode context) throws Exception {
if (context != null) {
// 获取 type 节点的属性, 默认是 PERPETUAL
String type = context.getStringAttribute("type", "PERPETUAL");
// 通过 type 值, 查找对应 Cache 接口的实现
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
// eviction 属性, eviction 对应的是回收策略, 默认为 LRU。
String eviction = context.getStringAttribute("eviction", "LRU");
// 解析 eviction 属性指定的 Cache 装饰器类型
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
// flushInterval 对应刷新间隔, 单位毫秒, 默认值不设置, 即没有刷新间隔, 缓存仅仅在刷新语句时刷新。
Long flushInterval = context.getLongAttribute("flushInterval");
// size 对应为引用的数量,即最多的缓存对象数据。
Integer size = context.getIntAttribute("size");
// readOnly 为只读属性, 默认为 false, 即可读写
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
// blocking 为阻塞, 默认值为 false。 当指定为 true 时将采用 BlockingCache 进行封装
boolean blocking = context.getBooleanAttribute("blocking", false);
// 获取 <cache> 属性节点下的子节点, 用于初始化二级缓存
Properties props = context.getChildrenAsProperties();
// 通过 MapperBuilderAssistant 创建 Cache 对象, 并将其添加到 COnfiguration 中
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}

其中, type 的对应类型 PERPETUAL

// PerpetualCache.class 为 org.apache.ibatis.cache.impl.PerpetualCache
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);

其他的就是获取属性, 有的有对应的默认值。

最后需要将这些属性, 通过 MapperBuilderAssistant.useNewCache() 进行缓存设置。

  public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
// 建造者模式
Cache cache = new CacheBuilder(currentNamespace)
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
// 将对象添加到 configuration 中
configuration.addCache(cache);
// 给当前命名空间的缓存成员变量赋值
currentCache = cache;
return cache;
}

该函数创建对应的 Cache 对象, 该对象的 idcurrentNamespace(当前mapper.xml 的 namespace)

  public Cache build() {
// 设置默认的实现, type 和 lru 对应的类不为空
setDefaultImplementations();
// 通过反射创建对象
Cache cache = newBaseCacheInstance(implementation, id);
// 根据<cache>节点的子节点<property>, 初始化Cache对象
setCacheProperties(cache);
// issue #352, do not apply decorators to custom caches
// 如果是PerpetualCache类型, 使用 decorators 中的装饰器来包装cache, 并设置属性
if (PerpetualCache.class.equals(cache.getClass())) {
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
// mybatis 自己提供的标准装饰器
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
// 如果不是 LoggingCache 子类, 则添加 LoggingCache 装饰器
cache = new LoggingCache(cache);
}
return cache;
}

将对象添加到 configuratin 中。

  public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}

对应的成员变量为

  protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");

StrictMap 类型。该对象将 namespace 与 缓存对象 Cache 对应起来了。 而 namespacexxxMapper.xml 的标识。

3 StrictMap

StrictMap 有什么特殊的地方, 为什么不直接用 HashMap 呢?

3.1 区别HashMap:键必须为String

protected static class StrictMap<V> extends HashMap<String, V>

3.2 区别HashMap:多了成员变量 name

多了一个 name 成员变量, 而且该变量是必须设置的

所有的构造函数都需要

    public StrictMap(String name, int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.name = name;
} public StrictMap(String name, int initialCapacity) {
super(initialCapacity);
this.name = name;
} public StrictMap(String name) {
super();
this.name = name;
} public StrictMap(String name, Map<String, ? extends V> m) {
super(m);
this.name = name;
}

3.3 区别HashMap:key 的处理多了一些变化

3.3.1 put

    public V put(String key, V value) {
// 是否存在 key, 存在则直接报异常
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key);
}
// 获取 shortKey
if (key.contains(".")) {
// 将 key 以 . 分割, 并获取最后一项作为 shortKey
final String shortKey = getShortName(key);
if (super.get(shortKey) == null) {
// 如果 shorKey 对应在 Map 中没有值, 则放入
super.put(shortKey, value);
} else {
// 如果 shorKey 对应在 Map 中有值, 则放入一个 Ambiguity 类
super.put(shortKey, (V) new Ambiguity(shortKey));
}
}
// key 也会放一个 value
return super.put(key, value);
}

3.3.2 shortKey

关于 shortKey, 其实就是我们以全限定名作为属性时, 它取得是分隔符分割后最后的一项。

// 将 key 以 . 分割, 并获取最后一项作为 shortKey
private String getShortName(String key) {
final String[] keyParts = key.split("\\.");
return keyParts[keyParts.length - 1];
}

shortKey 它的作用就是类似一个模糊查询的功能, 比如说我们要调用的是 com.mybatis.homejim.mapper.StudentMapper.selectAll 这个函数, 我们可以写

selectList("com.mybatis.homejim.mapper.StudentMapper.selectAll");

mybatis 中加入 shortKey 之后, 我们只需要写

selectList("selectAll");

但是, 在实际使用时用处不大, 很多函数基本都是会是二义性的, 不明白为何不取消。

3.3.3 Ambiguity

AmbiguityStrictMap 中的静态内部类。

protected static class Ambiguity {
final private String subject; public Ambiguity(String subject) {
this.subject = subject;
} public String getSubject() {
return subject;
}
}

其作用记录存在二义性的 key, 告诉使用者, 你的这个 key 是二义性的。

3.3.4 get


public V get(Object key) {
// value 为空则报错
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(name + " does not contain value for " + key);
}
// 二义性也报错
if (value instanceof Ambiguity) {
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
+ " (try using the full name including the namespace, or rename one of the entries)");
}
// 正常情况下应该是返回
return value;
}

一起学 mybatis

你想不想来学习 mybatis? 学习其使用和源码呢?那么, 在博客园关注我吧!!

我自己打算把这个源码系列更新完毕, 同时会更新相应的注释。快去 star 吧!!

mybatis最新源码和注释

mybatis源码-解析配置文件(四-1)之配置文件Mapper解析(cache)的更多相关文章

  1. mybatis源码分析(三)------------映射文件的解析

    本篇文章主要讲解映射文件的解析过程 Mapper映射文件有哪几种配置方式呢?看下面的代码: <!-- 映射文件 --> <mappers> <!-- 通过resource ...

  2. MyBatis源码分析(1)-MapConfig文件的解析

    1.简述 MyBatis是一个优秀的轻ORM框架,由最初的iBatis演化而来,可以方便的完成sql语句的输入输出到java对象之间的相互映射,典型的MyBatis使用的方式如下: String re ...

  3. MyBatis源码分析(四):SQL执行过程分析

    一.获取Mapper接口的代理 根据上一节,Mybatis初始化之后,利用sqlSession(defaultSqlSession)的getMapper方法获取Mapper接口 1 @Override ...

  4. mybatis源码分析(四)---------------代理对象的生成

    在mybatis两种开发方式这边文章中,我们提到了Mapper动态代理开发这种方式,现在抛出一个问题:通过sqlSession.getMapper(XXXMapper.class)来获取代理对象的过程 ...

  5. 【mybatis源码学习】mybtias基础组件-占位符解析器

    一.占位符解析器源码 1.占位符解析器实现的目标 通过解析字符串中指定前后缀中的字符,并完成相应的功能. 在mybtias中的应用,主要是为了解析Mapper的xml中的sql语句#{}中的内容,识别 ...

  6. mybatis 源码分析(四)一二级缓存分析

    本篇博客主要讲了 mybatis 一二级缓存的构成,以及一些容易出错地方的示例分析: 一.mybatis 缓存体系 mybatis 的一二级缓存体系大致如下: 首先当一二级缓存同时开启的时候,首先命中 ...

  7. mybatis源码学习(三):MappedStatement的解析过程

    我们之前介绍过MappedStatement表示的是XML中的一个SQL.类当中的很多字段都是SQL中对应的属性.我们先来了解一下这个类的属性: public final class MappedSt ...

  8. mybatis源码学习(四):动态SQL的解析

    之前的一片文章中我们已经了解了MappedStatement中有一个SqlSource字段,而SqlSource又有一个getBoundSql方法来获得BoundSql对象.而BoundSql中的sq ...

  9. mybatis源码-解析配置文件(四)之配置文件Mapper解析

    在 mybatis源码-解析配置文件(三)之配置文件Configuration解析 中, 讲解了 Configuration 是如何解析的. 其中, mappers作为configuration节点的 ...

随机推荐

  1. 2017.9.16~17,热烈庆祝共创力罗老师《敏捷MINI体验式实战培训》在某大型企业成功举办!

    2017.9.16~17日,深圳市共创力企业管理咨询有限公司为某上市企业提供了为期两天的内训服务.该次内训的主题为<敏捷MINI体验式实践培训>,为期两天.此次培训由共创力资深讲师Geor ...

  2. mssql sql server 其它系统函数 parsename 点语法字符串分割函数应用简介

    转自:http://www.maomao365.com/?p=4534 一. parsename函数功能简介 parsename函数的主要功能是:可以快速的使用”.”关键字分解字符串,并返回.分解后指 ...

  3. python 函数参数为*和**的作用与区别

    def function(*args):print(args) 中*的作用:表示此时参数为一个元祖. def function(**args):print(args)中**的作用:表示此时参数为一个字 ...

  4. Windows单机最大TCP连接数的问题

    本文和大家分享一下Windows下单机最大TCP连接数,因为在做Socket 编程时,我们经常会要问,单机最多可以建立多少个 TCP 连接,本文将介绍如何调整系统参数来调整单机的最大TCP连接数. W ...

  5. php 计算出一年中每周的周一日期

    最近接到一个任务,归纳起来,就是:要算出每年当中,每周的周一日期.想了一会,看了下date函数,深入了解了一下date函数各个参数的含义之后,终于把这道题做出来了! 在date()函数中,有一个参数对 ...

  6. June 7. 2018 Week 23rd Thursday

    Half is worse than none at all. 一知半解比一无所知更痛苦. From Westworld. If we go looking for the truth, get th ...

  7. 力扣算法题—069x的平方根

    实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: 4 输出: 2 示例 ...

  8. MonkeyRunner测试工具小结

    一.MonkeyRunner介绍: MonkeyRunner是Google提供的一个基于坐标点的Android黑盒自动化测试工具.Monkeyrunner工具提供了一套API让用户/测试人员来调用,调 ...

  9. Jenkins的环境部署

    一.Tomcat环境安装 1.安装JDK(Java环境) JDK下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index. ...

  10. Java面试知识点之虚拟机篇(一)

    前言:Java虚拟机的重要性不言而喻,不管是在实际工作中,还是面试中. 1.JVM架构 要点: 主要了解Java虚拟机运行时数据区:程序计数器.Java虚拟机栈.本地方法栈.Java堆和方法区. 参考 ...