Mybatis懒加载的实现

因为通过javassist和cglib代理实现的,所以说到底最主要的就是JavasisstProxyFactory类中的invoke方法和里面的load方法。

其实读一读,里面的逻辑就是跟配置中定义的规则一样的
因为github上的mybatis中文版中这部分注释比较少,所以从网上寻找博客,截取了代码注释片段记录下。
JavasisstProxyFactory

public class JavassistProxyFactory implements org.apache.ibatis.executor.loader.ProxyFactory {

 /**
 * 接口实现
 * @param target 目标结果对象
 * @param lazyLoader 延迟加载对象
 * @param configuration 配置
 * @param objectFactory 对象工厂
 * @param constructorArgTypes 构造参数类型
 * @param constructorArgs 构造参数值
 * @return
 */
 @Override
 public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
 return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
 }

 //省略...

 /**
 * 代理对象实现,核心逻辑执行
 */
 private static class EnhancedResultObjectProxyImpl implements MethodHandler {

 /**
 * 创建代理对象
 * @param type
 * @param callback
 * @param constructorArgTypes
 * @param constructorArgs
 * @return
 */
 static Object crateProxy(Class<?> type, MethodHandler callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {

 ProxyFactory enhancer = new ProxyFactory();
 enhancer.setSuperclass(type);

 try {
  //通过获取对象方法,判断是否存在该方法
  type.getDeclaredMethod(WRITE_REPLACE_METHOD);
  // ObjectOutputStream will call writeReplace of objects returned by writeReplace
  if (log.isDebugEnabled()) {
  log.debug(WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this");
  }
 } catch (NoSuchMethodException e) {
  //没找到该方法,实现接口
  enhancer.setInterfaces(new Class[]{WriteReplaceInterface.class});
 } catch (SecurityException e) {
  // nothing to do here
 }

 Object enhanced;
 Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
 Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
 try {
  //创建新的代理对象
  enhanced = enhancer.create(typesArray, valuesArray);
 } catch (Exception e) {
  throw new ExecutorException("Error creating lazy proxy. Cause: " + e, e);
 }
 //设置代理执行器
 ((Proxy) enhanced).setHandler(callback);
 return enhanced;
 }

  /**
  * 代理对象执行
  * @param enhanced 原对象
  * @param method 原对象方法
  * @param methodProxy 代理方法
  * @param args 方法参数
  * @return
  * @throws Throwable
  */
 @Override
 public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
  final String methodName = method.getName();
  try {
  synchronized (lazyLoader) {
   if (WRITE_REPLACE_METHOD.equals(methodName)) {
   //忽略暂未找到具体作用
   Object original;
   if (constructorArgTypes.isEmpty()) {
    original = objectFactory.create(type);
   } else {
    original = objectFactory.create(type, constructorArgTypes, constructorArgs);
   }
   PropertyCopier.copyBeanProperties(type, enhanced, original);
   if (lazyLoader.size() > 0) {
    return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
   } else {
    return original;
   }
   } else {
    //延迟加载数量大于0
   if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
    //aggressive 一次加载性所有需要要延迟加载属性或者包含触发延迟加载方法
    if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
    log.debug("==> laze lod trigger method:" + methodName + ",proxy method:" + methodProxy.getName() + " class:" + enhanced.getClass());
    //一次全部加载
    lazyLoader.loadAll();
    } else if (PropertyNamer.isSetter(methodName)) {
    //判断是否为set方法,set方法不需要延迟加载
    final String property = PropertyNamer.methodToProperty(methodName);
    lazyLoader.remove(property);
    } else if (PropertyNamer.isGetter(methodName)) {
    final String property = PropertyNamer.methodToProperty(methodName);
    if (lazyLoader.hasLoader(property)) {
     //延迟加载单个属性
     lazyLoader.load(property);
     log.debug("load one :" + methodName);
    }
    }
   }
   }
  }
  return methodProxy.invoke(enhanced, args);
  } catch (Throwable t) {
  throw ExceptionUtil.unwrapThrowable(t);
  }
 }
 }

load方法

/**
  * 执行懒加载查询,获取数据并且set到userObject中返回
  * @param userObject
  * @throws SQLException
  */
 public void load(final Object userObject) throws SQLException {

  //合法性校验
  if (this.metaResultObject == null || this.resultLoader == null) {
  if (this.mappedParameter == null) {
   throw new ExecutorException("Property [" + this.property + "] cannot be loaded because "
     + "required parameter of mapped statement ["
     + this.mappedStatement + "] is not serializable.");
  }

  //获取mappedstatement并且校验
  final Configuration config = this.getConfiguration();
  final MappedStatement ms = config.getMappedStatement(this.mappedStatement);
  if (ms == null) {
   throw new ExecutorException("Cannot lazy load property [" + this.property
     + "] of deserialized object [" + userObject.getClass()
     + "] because configuration does not contain statement ["
     + this.mappedStatement + "]");
  }

  //使用userObject构建metaobject,并且重新构建resultloader对象
  this.metaResultObject = config.newMetaObject(userObject);
  this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter,
    metaResultObject.getSetterType(this.property), null, null);
  }

  /* We are using a new executor because we may be (and likely are) on a new thread
  * and executors aren't thread safe. (Is this sufficient?)
  *
  * A better approach would be making executors thread safe. */
  if (this.serializationCheck == null) {
  final ResultLoader old = this.resultLoader;
  this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement,
    old.parameterObject, old.targetType, old.cacheKey, old.boundSql);
  }

  //获取数据库查询结果并且set到结果对象返回
  this.metaResultObject.setValue(property, this.resultLoader.loadResult());
 }

参考地址:
https://www.cnblogs.com/qixidi/p/10251126.html
https://blog.csdn.net/mingtian625/article/details/47358003

到此这篇关于Mybatis懒加载的实现的文章就介绍到这了,更多相关Mybatis 懒加载内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解如何实现Element树形控件Tree在懒加载模式下的动态更新

    Element提供的Tree树形控件,可以用清晰的层级结构展示信息,还可以展开或折叠.Tree支持两种加载模式:一次性加载全部树节点和懒加载模式.所谓懒加载模式,是指当需要展开父节点时才渲染子节点.懒加载模式的应用场景适合树节点数据量大的情形,在一定程度上可以优化图形用户界面的响应效率以及提升用户体验.但是,懒加载模式对数据动态刷新应用需求的支持不尽如意.树形控件节点一旦展开就缓存在本地,后续不会再继续更新和刷新节点数据.本文将介绍如何实现Element树形控件Tree在懒加载模式下的动态更新.

  • Vue自定义图片懒加载指令v-lazyload详解

    Vue是可以自定义指令的,最近学习过程中遇见了一个需要图片懒加载的功能,最后参考了别人的代码和思路自己重新写了一遍.以下将详细介绍如何实现自定义指令v-lazyload. 先看如何使用这个指令: <img v-lazyload="imageSrc" > imageSrc是要加载的图片的实际路径. 为了实现这个指令,我们首先单独建立一个文件,名字为lazyload.js.并填写基本的代码,如下: //Vue 图片懒加载,导出模块 export default (Vue , o

  • js前端实现图片懒加载(lazyload)的两种方式

    在实际的项目开发中,我们通常会遇见这样的场景:一个页面有很多图片,而首屏出现的图片大概就一两张,那么我们还要一次性把所有图片都加载出来吗?显然这是愚蠢的,不仅影响页面渲染速度,还浪费带宽.这也就是们通常所说的首屏加载,技术上现实其中要用的技术就是图片懒加载--到可视区域再加载. 思路: 将页面里所有img属性src属性用data-xx代替,当页面滚动直至此图片出现在可视区域时,用js取到该图片的data-xx的值赋给src. 关于各种宽高: 页可见区域宽: document.body.clien

  • 深入研究jQuery图片懒加载 lazyload.js使用方法

    lazyload是一个用Javascript编写的jQuery插件,它可以延迟加载长页面中的图片,在浏览器可视区域外的图片将不会被载入,直到用户将它们滚动到它们所在的位置. 跟bootstrap一样,lazyload.js也是依赖于jQuery <script src="resources/js/jquery-1.8.3.min.js"></script> <script src="resources/js/jquery.lazyload.min

  • 基于javascript实现图片懒加载

    一.定义 图片延迟加载也称为懒加载,延迟加载图片或符合某些条件时才加载某些图片,通常用于图片比较多的网页.可以减少请求数或者延迟请求数,优化性能.  二.呈现形式 [1]延时加载,使用setTimeout或setInterval进行加载延迟,如果用户在加载前就离开,自然就不会进行加载. [2]条件加载,符合某些条件或者触发了某些条件才开始异步加载. [3]可视区域加载,仅仅加载用户可以看到的区域,这个主要监控滚动条来实现,一般距离用户看到的底边很近的时候开始加载,这样能保证用户下拉时图片正好接上

  • jquery实现异步加载图片(懒加载图片一种方式)

    首先将插件在jq后面引入 (function($) { // alert($.fn.scrollLoading); $.fn.scrollLoading = function(options) { var defaults = { attr: "data-url" }; var params = $.extend({}, defaults, options || {}); params.cache = []; $(this).each(function() { var node = t

  • vue2组件实现懒加载浅析

    一. 什么是懒加载 懒加载也叫延迟加载,即在需要的时候进行加载,随用随载. 二.为什么需要懒加载 在单页应用中,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时 三.如何与webpack配合实现组件懒加载 1.在webpack配置文件中的output路径配置chunkFilename属性 output: { pat

  • 微信小程序实现图片懒加载的示例代码

    本文主要介绍微信小程序的模拟图片懒加载,实现的原理是通过页面预加载图片(默认图),加载完成后再显示出来原图,而非真正意义上的懒加载(跟web的懒加载还有很大的差距),只是借此提高用户体验度. 多图片懒加载 1.xml页面 <block wx:for="{{list}}" wx:key=""> <image class='relative width-100 mgb-20 fade_in' src='{{item.cover_url}}' mode=

  • 基于jquery的图片懒加载js

    以下是实现代码(基于jquery): 复制代码 代码如下: function lazyload(option){ var settings={ defObj:null, defHeight:0 }; settings=$.extend(settings,option||{}); var defHeight=settings.defHeight,defObj=(typeof settings.defObj=="object")?settings.defObj.find("img

  • Mybatis懒加载的实现

    因为通过javassist和cglib代理实现的,所以说到底最主要的就是JavasisstProxyFactory类中的invoke方法和里面的load方法. 其实读一读,里面的逻辑就是跟配置中定义的规则一样的 因为github上的mybatis中文版中这部分注释比较少,所以从网上寻找博客,截取了代码注释片段记录下. JavasisstProxyFactory public class JavassistProxyFactory implements org.apache.ibatis.exec

  • Mybatis如何实现关联属性懒加载

    Mybatis 关联属性懒加载 延迟加载配置 mybatis默认没有开启延迟加载,需要在config.xml中setting配置. lazyLoadingEnabled:true使用延迟加载,false禁用延迟加载,默认为false. aggressiveLazyLoading:true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性.false,当延迟加载时,按需加载对象属性(即访问对象中一个对象属性时,不会加载对象中的引用属性).默认为true. 修改延

  • MyBatis深入解读懒加载的实现

    懒加载 ,也称为嵌套查询 需要查询关联信息时,使用 Mybatis 懒加载特性可有效的减少数据库压力, 首次查询只查询主表信息,关联表的信息在用户获取时再加载. Mybatis 一对一关联的 association 和一对多的 collection 可以实现懒加载.懒加载时要 使用resultMap,不能使用 resultType . 这里我们以员工表和部门表为例 通过deptId 与 部门表 id 关联 我们这里首先需要开启一个设置 <settings> <!--指定哪些方法去触发延迟

  • mybatis源码解读之executor包懒加载功能 

    ProxyFactory是创建代理类的工厂接口,其中的setProperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置.createProxy方法用来创建一个代理对象 public interface ProxyFactory {   // 设置工厂属性   default void setProperties(Properties properties) {   }   // 创建代理对象   Object createProxy(O

  • MyBatis的注解使用、ORM层优化方式(懒加载和缓存)

    目录 Mybatis注解 Mybatis对ORM层的优化 缓存 懒加载 MyBatis缓存机制 二级缓存 Mybatis注解 查找 @Select( "SELECT * FROM tt_user WHERE username Like #{id};") User findUserByName(String name); <!--以map为输入参数查找--> @Select("select * from tt_user where username= #{name}

  • 解决JPA @OneToMany及懒加载无效的问题

    目录 JPA @OneToMany及懒加载无效 @OneToMany 小结一下吧 实现JPA的懒加载和无外键 例如 转换时使用 JPA @OneToMany及懒加载无效 @OneToOne @ManyToMany使用不做过多解释,重点解决"懒加载无效问题". 示例: @OneToMany teacher 和 student是一对多关系 只需要在studentList上使用@OneToMany注解,对应的参数为 懒加载.级联操作.子表外键 我为了验证懒加载是否生效,在debug模式下发现

  • mybatis一直加载xml,找到错误的解决方案

    目录 mybatis一直加载xml,找到错误 今天终于找到了一种解决方法 mybatis延迟加载(xml) 在mybatis的配置文件中 mybatis一直加载xml,找到错误 我们在写springmvc+mybatis项目,启动项目的时候,mapper配置文件一直刷,一直加载..... 对于我们伟大的程序猿来说这并不可怕,可怕的是没有错误打印出来.....完全不知道如何下手啊, 今天终于找到了一种解决方法 找到org.springframework.beans.factory.support.

  • 使用jpa的实体对象转json符串时懒加载的问题及解决

    目录 解决转json符串时懒加载问题方法(1) 解决转json符串时懒加载问题方法(2) Rest风格中关于JPA使用懒加载的坑 解决转json符串时懒加载问题方法(1) 1.导入hibernate5转json的Maven依赖: <dependency>     <groupId>com.fasterxml.jackson.datatype</groupId>     <artifactId>jackson-datatype-hibernate5</a

  • 浅谈vue中使用图片懒加载vue-lazyload插件详细指南

    在vue中使用图片懒加载详细指南,分享给大家.具体如下: 说明 当网络请求比较慢的时候,提前给这张图片添加一个像素比较低的占位图片,不至于堆叠在一块,或显示大片空白,让用户体验更好一点. 使用方式 使用vue的 vue-lazyload 插件 插件地址:https://www.npmjs.com/package/vue-lazyload 案例 demo: 懒加载案例demo Installation 安装方式 npm $ npm i vue-lazyload -D CDN CDN: https:

  • 浅谈angular懒加载的一些坑

    写在前面 最近在工作中接触到angular模块化打包加载的一些内容,感觉中间踩了一些坑,在此标记一下. 项目背景: 项目主要用到angularJs作为前端框架,项目之前发布的时候会把所有的前端脚本打包压缩到一个文件中,在页面初次访问的时候加载,造成页面初始载入缓慢,在此基础上,提出按需加载,即只有当用户访问某个模块的时候,该模块的脚本才会加载. 工具类: 项目使用grunt打包根据AMD规范,使用grunt-contrib-requirejs来压缩合并模块,同时用ocLazyLoad来完成ang

随机推荐