java实现懒加载_Mybatis懒加载的实现

本文详细解析了Mybatis中懒加载的实现原理,主要关注JavassistProxyFactory类和EnhancedResultObjectProxyImpl代理对象的逻辑。通过代理对象在特定方法调用时触发懒加载,实现数据的按需加载。
摘要由CSDN通过智能技术生成

因为通过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());

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值