我们知道在Mybatis中支持延迟加载,什么是懒加载呢? 顾名思义就是在需要的时候再加载数据,而不是一开始就准备好数据。那么是如何实现延迟加载的呢?在DefaultResultSetHandler类中有这样一段代码,就是通过创建一个代理对象实现了懒加载,在调用相关方法的时候进行加载数据。
//如果属性映射存在嵌套查询ID且配置了懒加载
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
//创建代理对象
resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
目前默认的ProxyFactory是
JavassistProxyFactory 所以本次代码也是分析JavassistProxyFactory的源码
public Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List
public class Author implements Serializable {
protected int id;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
System.out.println("readObject");
in.defaultReadObject();
}
private void writeObject(ObjectOutputStream out) throws IOException{
System.out.println("writeObject");
out.defaultWriteObject();
}
Object writeReplace() throws ObjectStreamException{
System.out.println("writeReplace");
Author replaced=new Author();
replaced.setId(123);
return replaced;
}
@Test
public void testSeria() throws Exception{
Author author=new Author();
author.setId(456);
Serializable result= deserialize(serialize((Serializable)author));
System.out.println(((Author)result).getId());
}
protected byte[] serialize(Serializable value) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(value);
oos.flush();
oos.close();
return bos.toByteArray();
}
protected Serializable deserialize(byte[] value) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(value);
ObjectInputStream ois = new ObjectInputStream(bis);
Serializable result = (Serializable) ois.readObject();
ois.close();
return result;
}
这段测试代码的结果应该是什么呢?反序列化后的ID还是456吗?实际的输出结果是:
writeReplace
writeObject
readObject
123
Object readResolve(){
Author author=new Author();
author.setId(987);
System.out.println("readResolve");
return author;
}
此时的输出结果是:
writeReplace
writeObject
readObject
readResolve
987
这个是为什么呢?还是通过一下简单的时序图看一下
@Override
public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
final String methodName = method.getName();
try {
synchronized (lazyLoader) {
//如果当前调用是writeReplace 则表示需要对象当前对象进行序列化,而当前对象是一个代理对象,直接对当前对象序列化显然是不合理的
//在上面的代码可以发现代理对对象都存在writeReplace方法,在序列化的时候会调用该方法,在对该方法进行增强处理返回原始对对象,如果需要延迟加载
//则返回了一个序列化状态保持对象
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 {// 如果不是writeReplace方法
//如果懒加载对象大于0且当前不是finalize方法
if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
//如果是积极的懒加载模式或者调用列触发加载全部方法则加载全部懒加载属性
if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
lazyLoader.loadAll();
} else if (PropertyNamer.isSetter(methodName)) {
//如果setter的属性是懒加载的则从懒加载映射表中删除
final String property = PropertyNamer.methodToProperty(methodName);
lazyLoader.remove(property);
} else if (PropertyNamer.isGetter(methodName)) {
//如果getter的属性是懒加载的此时需要加载
final String property = PropertyNamer.methodToProperty(methodName);
if (lazyLoader.hasLoader(property)) {
lazyLoader.load(property);
}
}
}
}
}
return methodProxy.invoke(enhanced, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
class JavassistSerialStateHolder extends AbstractSerialStateHolder {
private static final long serialVersionUID = 8940388717901644661L;
public JavassistSerialStateHolder() {
}
public JavassistSerialStateHolder(
final Object userBean,
final Map unloadedProperties,
final ObjectFactory objectFactory,
List> constructorArgTypes,
List
@Override
public final void writeExternal(final ObjectOutput out) throws IOException {
boolean firstRound = false;
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream os = stream.get();
if (os == null) {
os = new ObjectOutputStream(baos);
firstRound = true;
stream.set(os);
}
//序列化userBean
os.writeObject(this.userBean);
//序列化未加载属性
os.writeObject(this.unloadedProperties);
//序列化对象工厂
os.writeObject(this.objectFactory);
//序列化构造参数类型
os.writeObject(this.constructorArgTypes);
//序列化构造参数
os.writeObject(this.constructorArgs);
final byte[] bytes = baos.toByteArray();
//完成序列化
out.writeObject(bytes);
if (firstRound) {
stream.remove();
}
}
@Override
public final void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
//反序列化
final Object data = in.readObject();
if (data.getClass().isArray()) {
this.userBeanBytes = (byte[]) data;
} else {
this.userBean = data;
}
}
@SuppressWarnings("unchecked")
protected final Object readResolve() throws ObjectStreamException {
//如果userBean不为null且userBeanBytes长度为0则表示已经完成过 直接返回该对象
if (this.userBean != null && this.userBeanBytes.length == 0) {
return this.userBean;
}
/*第一次 */
try {
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(this.userBeanBytes));
//反序列化userBean
this.userBean = in.readObject();
//反序列化延迟加载属性
this.unloadedProperties = (Map) in.readObject();
//反序列化对象工厂
this.objectFactory = (ObjectFactory) in.readObject();
//反序列化构造参数类型
this.constructorArgTypes = (Class[]) in.readObject();
//反序列化构造参数
this.constructorArgs = (Object[]) in.readObject();
} catch (final IOException ex) {
throw (ObjectStreamException) new StreamCorruptedException().initCause(ex);
} catch (final ClassNotFoundException ex) {
throw (ObjectStreamException) new InvalidClassException(ex.getLocalizedMessage()).initCause(ex);
}
final Map arrayProps = new HashMap(this.unloadedProperties);
final List> arrayTypes = Arrays.asList(this.constructorArgTypes);
final List<Object> arrayValues = Arrays.asList(this.constructorArgs);
//根据序列化是保存的数据创建一个反序列化代理对象
return this.createDeserializationProxy(userBean, arrayProps, objectFactory, arrayTypes, arrayValues);
相关阅读:
本文来自网易实践者社区,经作者张伟授权发布。