开发者社区> 游客tqcqp5pa4cdy4> 正文

为什么建议框架源码学习从Mybatis开始(中)

简介: 为什么建议框架源码学习从Mybatis开始(中)
+关注继续查看

2、MapperProxy:就是上面创建代理时的增强

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
   --------------------------
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
}


针对非默认,非Object方法(也就是我们的业务方法),会封装成一个MapperMethod, 调

用的是MapperMethod.execute

3、MapperMethod

一个业务方法在执行时,会被封装成MapperMethod, MapperMethod 执行时,又会去调用了Sqlsession

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case SELECT:
        ...
        result = sqlSession.selectOne(command.getName(), param);
        ...
        break;
      ....
}

绕了一周,终究回到了最基本的调用方式上。

result = sqlSession.selectOne(command.getName(), param);
User user = sqlSession.selectOne("com.wqd.dao.UserMapper.getById", 1);

总结下:

  • 最基本用法=sqlsession.selectOne(statement.id,参数)
  • Mapper=User代理类getById---》MapperProxy.invoke方法---》MapperMethod.execute()---》sqlsession.selectOne(statement.id,参数)

显然这一绕,方便了开发人员,但是对于系统来说带来的是多余开销。


五、缓存


Mybatis 还加入了缓存的设计。

分为一级缓存和二级缓存


1.一级缓存

先看长什么样子?原来就是HashMap的封装

public class PerpetualCache implements Cache {
  private String id;
  private Map<Object, Object> cache = new HashMap<Object, Object>();
  public PerpetualCache(String id) {
    this.id = id;
  }
}

在什么位置?作为BaseExecutor的一个属性存在。

public abstract class BaseExecutor implements Executor {
 protected BaseExecutor(Configuration configuration, Transaction transaction) {
    this.localCache = new PerpetualCache("LocalCache");
 }
}

Executor上面说过,Sqlsession的能力其实是委托Executor完成的.Executor作为Sqlsession的一个属性存在。

所以:MyBatis一级缓存的生命周期和SqlSession一致


2.二级缓存

2.1基本信息

二级缓存在设计上相对与一级缓存就比较复杂了。

以xml配置为例,二级缓存需要配置开启,并配置到需要用到的namespace中。

<setting name="cacheEnabled" value="true"/>
<mapper namespace="mapper.StudentMapper">
    <cache/>
</mapper>


同一个namespace下的所有MappedStatement共用同一个二级缓存。二级缓存的生命周期跟随整个应用的生命周期,同时二级缓存也实现了同namespaceSqlSession数据的共享。


二级缓存配置开启后,其数据结构默认也是PerpetualCache。这个和一级缓存的一样。


但是在构建二级缓存时,mybatis使用了一个典型的设计模式装饰模式,对PerpetualCache进行了一层层的增强,使得二级缓存成为一个被层层装饰过的PerpetualCache,每装饰一层,就有不同的能力,这样一来,二级缓存就比一级缓存丰富多了。

装饰类有:

  • LoggingCache:日志功能,装饰类,用于记录缓存的命中率,如果开启了DEBUG模式,则会输出命中率日志
  • LruCache:采用了Lru算法的Cache实现,移除最近最少使用的Key/Value
  • ScheduledCache: 使其具有定时清除能力
  • BlockingCache: 使其具有阻塞能力
层层装饰
private Cache setStandardDecorators(Cache cache) {
    try {
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
        cache = new SerializedCache(cache);
      }
      cache = new LoggingCache(cache);
      cache = new SynchronizedCache(cache);
      if (blocking) {
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
  }


2.2如何工作

二级缓存的工作原理,还是用到装饰模式,不过这次装饰的Executor。使用CachingExecutor去装饰执行SQL的Executor

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);//装饰
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

当执行查询时,先从二级缓存中查询,二级缓存没有时才去走Executor的查询


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23607 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22387 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
19978 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
14801 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
22615 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36499 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
16604 0
84
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载