Mybatis懒加载的实现

网友投稿 290 2022-12-02


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 chttp://reating 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 properthttp://y = 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);

}fUYYzKutA 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,

fUYYzKutAmetaResultObject.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://cnblogs.com/qixidi/p/10251126.html

https://blog.csdn.net/mingtian625/article/details/47358003


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何改变idea和maven中的sdk版本
下一篇:IDEA的常见的设置和优化功能图文详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~