千家信息网

mybatis中如何实现executor包懒加载功能

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,这篇文章主要为大家展示了"mybatis中如何实现executor包懒加载功能 ",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"mybatis中如何实现ex
千家信息网最后更新 2024年09月22日mybatis中如何实现executor包懒加载功能

这篇文章主要为大家展示了"mybatis中如何实现executor包懒加载功能 ",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"mybatis中如何实现executor包懒加载功能 "这篇文章吧。

ProxyFactory是创建代理类的工厂接口,其中的setProperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置。createProxy方法用来创建一个代理对象

public interface ProxyFactory {  // 设置工厂属性  default void setProperties(Properties properties) {  }  // 创建代理对象  Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List constructorArgs);}

ProxyFactory接口有2个实现类,CglibProxyFactoryJavassistProxyFactor类。这两个实现类整体结构高度一致,内部类、方法设置都一样,只是实现原理不同。CglibProxyFactory基于cglib实现,JavassistProxyFactor基于javassist实现。

接下来以CglibProxyFactory类为源码进行分析:

CglibProxyFactory类中提供了两个创建代理对象的方法。其中createProxy方法重写了一个普通的代理对象,createDeserializationProxy方法用来创建一个反序列化的代理对象。

public class CglibProxyFactory implements ProxyFactory {  private static final String FINALIZE_METHOD = "finalize";  private static final String WRITE_REPLACE_METHOD = "writeReplace";  public CglibProxyFactory() {    try {      Resources.classForName("net.sf.cglib.proxy.Enhancer");    } catch (Throwable e) {      throw new IllegalStateException("Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.", e);    }  }  // 创建一个代理  @Override  public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List constructorArgs) {    return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);  }  // 创建一个反序列化的代理  public Object createDeserializationProxy(Object target, Map unloadedProperties, ObjectFactory objectFactory, List> constructorArgTypes, List constructorArgs) {    return EnhancedDeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs);  }  private static class EnhancedResultObjectProxyImpl implements MethodInterceptor {    // 被代理类    private final Class type;    // 要懒加载的属性Map    private final ResultLoaderMap lazyLoader;    // 是否是激进懒加载    private final boolean aggressive;    // 能够触发懒加载的方法名"equals", "clone", "hashCode", "toString"。这四个方法名在Configuration中被初始化。    private final Set lazyLoadTriggerMethods;    // 对象工厂    private final ObjectFactory objectFactory;    // 被代理类构造函数的参数类型列表    private final List> constructorArgTypes;    // 被代理类构造函数的参数列表    private final List constructorArgs;    private EnhancedResultObjectProxyImpl(Class type, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List constructorArgs) {      this.type = type;      this.lazyLoader = lazyLoader;      this.aggressive = configuration.isAggressiveLazyLoading();      this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods();      this.objectFactory = objectFactory;      this.constructorArgTypes = constructorArgTypes;      this.constructorArgs = constructorArgs;    }    public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List constructorArgs) {      final Class type = target.getClass();      EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);      Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);      PropertyCopier.copyBeanProperties(type, target, enhanced);      return enhanced;    }    /**     * 代理类的拦截方法     * @param enhanced 代理对象本身     * @param method 被调用的方法     * @param args 每调用的方法的参数     * @param methodProxy 用来调用父类的代理     * @return 方法返回值     * @throws Throwable     */    @Override    public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {      // 取出被代理类中此次被调用的方法的名称      final String methodName = method.getName();      try {        synchronized (lazyLoader) { // 防止属性的并发加载          if (WRITE_REPLACE_METHOD.equals(methodName)) { // 被调用的是writeReplace方法            // 创建一个原始对象            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) { // 存在懒加载属性              // 则此时返回的信息要更多,不仅仅是原对象,还有相关的懒加载的设置等信息。因此使用CglibSerialStateHolder进行一次封装              return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);            } else {              // 没有未懒加载的属性了,那直接返回原对象进行序列化              return original;            }          } else {            if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { // 存在懒加载属性且被调用的不是finalize方法              if (aggressive || lazyLoadTriggerMethods.contains(methodName)) { // 设置了激进懒加载或者被调用的方法是能够触发全局懒加载的方法                // 完成所有属性的懒加载                lazyLoader.loadAll();              } else if (PropertyNamer.isSetter(methodName)) { // 调用了属性写方法                // 则先清除该属性的懒加载设置。该属性不需要被懒加载了                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);                }              }            }          }        }        // 触发被代理类的相应方法。能够进行到这里的是除去writeReplace方法外的方法,例如读写方法、toString方法等        return methodProxy.invokeSuper(enhanced, args);      } catch (Throwable t) {        throw ExceptionUtil.unwrapThrowable(t);      }    }  }  }

代理类最核心的方法是intercept方法,当被代理对象的其他方法被调用时,intercept方法的处理方式是:

如果设置了激进懒加载或者被调用的是触发全局加载的方法,则直接加载所有未加载的属性。

如果被调用的是属性写方法,则将该方法从懒加载列表中删除,因为此时数据库中的数据已经不是最新的,没有必要再去加载,然后进行属性的写入操作。

如果被调用的是读方法,则该属性尚未被懒加载的情况下,则加载该属性,如果该属性已经被懒加载过,则直接读取该属性。

ResultLoaderMap类:

被代理对象可能会有多个属性可以被懒加载,这些尚未完成加载的属性是在ResultLoaderMap类的实例中存储的。ResultLoaderMap类主要就是一个map类,该类key为属性名的大写,value为LoadPair对象。LoadPair类是ResultLoaderMap类的内部类,它能实现对应属性的懒加载功能。

public static class LoadPair implements Serializable {    private static final long serialVersionUID = 20130412;      // 用来根据反射得到数据库连接的方法名    private static final String FACTORY_METHOD = "getConfiguration";        // 判断是否经过了序列化的标志位,因为该属性被设置了transient,经过一次序列化和反序列化后会变为null    private final transient Object serializationCheck = new Object();       // 输出结果对象的封装    private transient MetaObject metaResultObject;       // 用以加载未加载属性的加载器    private transient ResultLoader resultLoader;      // 日志记录器    private transient Log log;        // 用来获取数据库连接的工厂    private Class configurationFactory;        // 未加载的属性的属性名    private String property;       // 能够加载未加载属性的SQL的编号    private String mappedStatement;      // 能够加载未加载属性的SQL的参数    private Serializable mappedParameter;    private LoadPair(final String property, MetaObject metaResultObject, ResultLoader resultLoader) {      this.property = property;      this.metaResultObject = metaResultObject;      this.resultLoader = resultLoader;      if (metaResultObject != null && metaResultObject.getOriginalObject() instanceof Serializable) {        final Object mappedStatementParameter = resultLoader.parameterObject;        if (mappedStatementParameter instanceof Serializable) {          this.mappedStatement = resultLoader.mappedStatement.getId();          this.mappedParameter = (Serializable) mappedStatementParameter;          this.configurationFactory = resultLoader.configuration.getConfigurationFactory();        } else {          Log log = this.getLogger();          if (log.isDebugEnabled()) {            log.debug("Property [" + this.property + "] of ["                    + metaResultObject.getOriginalObject().getClass() + "] cannot be loaded "                    + "after deserialization. Make sure it's loaded before serializing "                    + "forenamed object.");          }        }      }    }    public void load() throws SQLException {      if (this.metaResultObject == null) {        throw new IllegalArgumentException("metaResultObject is null");      }      if (this.resultLoader == null) {        throw new IllegalArgumentException("resultLoader is null");      }      this.load(null);    }    /**     * 进行加载操作     * @param userObject 需要被懒加载的对象(只有当this.metaResultObject == null || this.resultLoader == null才生效,否则会采用属性metaResultObject对应的对象)     * @throws SQLException     */    public void load(final Object userObject) throws SQLException {      if (this.metaResultObject == null || this.resultLoader == null) { // 输出结果对象的封装不存在或者输出结果加载器不存在        // 判断用以加载属性的对应的SQL语句存在        if (this.mappedParameter == null) {          throw new ExecutorException("Property [" + this.property + "] cannot be loaded because "                  + "required parameter of mapped statement ["                  + this.mappedStatement + "] is not serializable.");        }        final Configuration config = this.getConfiguration();        // 取出用来加载结果的SQL语句        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 + "]");        }        // 创建结果对象的包装        this.metaResultObject = config.newMetaObject(userObject);        // 创建结果加载器        this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter,                metaResultObject.getSetterType(this.property), null, null);      }      // 只要经历过持久化,则可能在别的线程中了。为这次惰性加载创建的新线程ResultLoader      if (this.serializationCheck == null) {        // 取出原来的ResultLoader中的必要信息,然后创建一个新的        // 这是因为load函数可能在不同的时间多次执行(第一次加载属性A,又过了好久加载属性B)。        // 而该对象的各种属性是跟随对象的,加载属性B时还保留着加载属性A时的状态,即ResultLoader是加载属性A时设置的        // 则此时ResultLoader中的Executor在ResultLoader中被替换成了一个能运行的Executor,而不是ClosedExecutor        // 能运行的Executor的状态可能不是close,这将导致它被复用,从而引发多线程问题        // 是不是被两次执行的一个关键点就是有没有经过序列化,因为执行完后会被序列化并持久化        final ResultLoader old = this.resultLoader;        this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement,                old.parameterObject, old.targetType, old.cacheKey, old.boundSql);      }      this.metaResultObject.setValue(property, this.resultLoader.loadResult());    }    private Configuration getConfiguration() {      if (this.configurationFactory == null) {        throw new ExecutorException("Cannot get Configuration as configuration factory was not set.");      }      Object configurationObject;      try {        final Method factoryMethod = this.configurationFactory.getDeclaredMethod(FACTORY_METHOD);        if (!Modifier.isStatic(factoryMethod.getModifiers())) {          throw new ExecutorException("Cannot get Configuration as factory method ["                  + this.configurationFactory + "]#["                  + FACTORY_METHOD + "] is not static.");        }        if (!factoryMethod.isAccessible()) {          configurationObject = AccessController.doPrivileged((PrivilegedExceptionAction) () -> {            try {              factoryMethod.setAccessible(true);              return factoryMethod.invoke(null);            } finally {              factoryMethod.setAccessible(false);            }          });        } else {          configurationObject = factoryMethod.invoke(null);        }      } catch (final ExecutorException ex) {        throw ex;      } catch (final NoSuchMethodException ex) {        throw new ExecutorException("Cannot get Configuration as factory class ["                + this.configurationFactory + "] is missing factory method of name ["                + FACTORY_METHOD + "].", ex);      } catch (final PrivilegedActionException ex) {        throw new ExecutorException("Cannot get Configuration as factory method ["                + this.configurationFactory + "]#["                + FACTORY_METHOD + "] threw an exception.", ex.getCause());      } catch (final Exception ex) {        throw new ExecutorException("Cannot get Configuration as factory method ["                + this.configurationFactory + "]#["                + FACTORY_METHOD + "] threw an exception.", ex);      }      if (!(configurationObject instanceof Configuration)) {        throw new ExecutorException("Cannot get Configuration as factory method ["                + this.configurationFactory + "]#["                + FACTORY_METHOD + "] didn't return [" + Configuration.class + "] but ["                + (configurationObject == null ? "null" : configurationObject.getClass()) + "].");      }      return Configuration.class.cast(configurationObject);    }    private Log getLogger() {      if (this.log == null) {        this.log = LogFactory.getLog(this.getClass());      }      return this.log;    }  }

以上是"mybatis中如何实现executor包懒加载功能 "这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

属性 方法 对象 代理 序列 结果 工厂 功能 参数 数据 激进 两个 信息 内容 函数 尚未 接口 数据库 篇文章 线程 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 饥荒怎么看服务器历史 华硕天选开不了游戏服务器 服务器卡死ping不通 网络安全维护都有哪些方法 对网络安全进行自查 计算机网络技术和计算机应用技术有什么区别 服务器费用指的是什么 理财和购物软件开发 更改数据库编码格式 陕西省公安厅网络安全等级保护 内蒙古高校线上宣传网络安全知识 初中毕业学计算机网络技术 数据库系统概念df 网络安全教育视频网站 家庭普查数据库 软件开发仓储管理系统 惠普服务器换硬盘无法识别 学软件开发需要先有电脑吗 租用服务器合同 党委党组落实网络安全 触屏终端软件开发 河南创新网络技术服务代理品牌 未来网络技术发展与展望 北京创新乐知网络技术 视觉软件开发公司有哪些 大数据技术有没有软件开发 数据库事务属性是 郑州安卓应用软件开发公司哪个好 数据库老数据删不掉 windows磁盘映射服务器
0