Mybatis源码解析之核心类分析
Mybatis源码解析之初始化分析
Mybatis源码解析之执行流程解析
Mybatis源码解析之数据库连接和连接池
Mybatis源码解析之事务管理
Mybatis源码解析之缓存机制(一):一级缓存
Mybatis源码解析之缓存机制(二):二级缓存
Mybatis源码解析之插件机制
Mybatis源码解析之mapper接口的代理模式
Mybatis源码解析之DefaultResultSetHandler的handleResultSets方法解析
Mybatis源码解析之Spring集成mybatis-spring分析
Mybatis源码解析之懒加载(一):配置和ResultLoaderMap
一、ProxyFactory
在Mybatis源码解析之DefaultResultSetHandler的handleResultSets方法解析中我们已经分析到,在对查询得到的结果集处理成list时,由ProxyFactory查理懒加载问题。从接口命名就可以看出,mybatis懒加载使用的是代理模式。
public interface ProxyFactory {
void setProperties(Properties properties);
Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
}
Mybatis提供了两个实现类CglibProxyFactory和JavassistProxyFactory,分别基于org.javassist:javassist和cglib:cglib进行实现。
setProperties用于配置属性,用于使用者自定义实现类的时候进行扩展,CglibProxyFactory和JavassistProxyFactory实现的都只是个空方法。
createProxy方法就是实现懒加载逻辑的狠心方法,也是我们分析的目标。
二、CglibProxyFactory
CglibProxyFactory基于cglib动态代理模式,通过继承父类的方式生成动态代理类。
@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);
}
在CglibProxyFactory类中,createProxy方法通过静态内部类EnhancedResultObjectProxyImpl的createProxy静态方法方法实现。
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
final Class<?> type = target.getClass();
EnhancedResultObjectProxyImpl callback = new EnhancedResultObjectProxyImpl(type, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
//由CglibProxyFactory生成对象
Object enhanced = crateProxy(type, callback, constructorArgTypes, constructorArgs);
//复制属性
PropertyCopier.copyBeanProperties(type, target, enhanced);
return enhanced;
}
可以看到,由CglibProxyFactory的另一个同名的静态方法createProxy生成对象, PropertyCopier.copyBeanProperties进行属性的复制。
static Object crateProxy(Class<?> type, Callback callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(callback);
enhancer.setSuperclass(type);
//生成的对象必须要有writeReplace方法用于ObjectOutputStream
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;
if (constructorArgTypes.isEmpty()) {
enhanced = enhancer.create();
} else {
Class<?>[] typesArray = constructorArgTypes.toArray(new Class[constructorArgTypes.size()]);
Object[] valuesArray = constructorArgs.toArray(new Object[constructorArgs.size()]);
enhanced = enhancer.create(typesArray, valuesArray);
}
return enhanced;
}
可以看到,初始化Enhancer,并调用构造方法,生成对象。从enhancer.setSuperclass(type);
也能看出cglib采用的是继承父类的方式。
public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
Class<?> parent = type;
while (parent != null) {
final Field[] fields = parent.getDeclaredFields();
for(Field field : fields) {
try {
field.setAccessible(true);
field.set(destinationBean, field.get(sourceBean));
} catch (Exception e) {
// Nothing useful to do, will only fail on final fields, which will be ignored.
}
}
parent = parent.getSuperclass();
}
}
PropertyCopier的copyBeanProperties方法就是通过反射将原来对象的属性值交给代理对象。
三、 CglibProxyFactory$EnhancedResultObjectProxyImpl
EnhancedResultObjectProxyImpl实现了MethodInterceptor接口,此接口是Cglib拦截目标对象方法的入口,对目标对象方法的调用都会通过此接口的intercept的方法。
private EnhancedResultObjectProxyImpl(Class<?> type, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
this.type = type;
this.lazyLoader = lazyLoader;
this.aggressive = configuration.isAggressiveLazyLoading();
this.lazyLoadTriggerMethods = configuration.getLazyLoadTriggerMethods();
this.objectFactory = objectFactory;
this.constructorArgTypes = constructorArgTypes;
this.constructorArgs = constructorArgs;
}
@Override
public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
final String methodName = method.getName();
try {
synchronized (lazyLoader) {
//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 CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
} else {
return original;
}
} else {
if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
//全部加载
if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
lazyLoader.loadAll();
} else if (PropertyNamer.isSetter(methodName)) {
//通过set赋值了,后续不需要懒加载
final String property = PropertyNamer.methodToProperty(methodName);
lazyLoader.remove(property);
} else if (PropertyNamer.isGetter(methodName)) {
//get方法按需加载
final String property = PropertyNamer.methodToProperty(methodName);
if (lazyLoader.hasLoader(property)) {
lazyLoader.load(property);
}
}
}
}
}
//执行原方法(即父类方法)
return methodProxy.invokeSuper(enhanced, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
可以看到:
(1)writeReplace方法:该方法在cglib用于ObjectOutputStream,因此需要初始化并返回原来的对象或封装后的CglibSerialStateHolder。
(2)aggressiveLazyLoading为true或者执行的是懒加载触发方法(默认toString, hashcode, clone, equals),加载所有懒加载的属性。(全部加载)
(3)set方法,说明已经进行赋值,该属性不在需要懒加载。
(4)get方法,如果该属性属于懒加载属性,进行加载。(按需加载)
最后,执行父类的方法,也就是原来的对象的方法逻辑。
四、JavassistProxyFactory
JavassistProxyFactory使用的是javassist方式,直接修改class文件的字节码格式。
@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);
}
public static Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> 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;
}
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;
}
JavassistPorxyFactory的createProxy方法的调用层次和代码和CglibProxyFactory及其相似。
五、JavassistProxyFactory$EnhancedResultObjectProxyImpl
EnhancedResultObjectProxyImpl实现了MethodHandler,这个接口是cglib拦截目标对象方法的接口,核心方法是invoke方法。
@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 {
if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
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);
}
}
}
}
}
return methodProxy.invoke(enhanced, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
可以看到,其逻辑和CglibProxyFactory的也极其类似。
(1)writeReplace方法:该方法在cglib用于ObjectOutputStream,因此需要初始化并返回原来的对象或封装后的JavassistSerialStateHolder。
(2)aggressiveLazyLoading为true或者执行的是懒加载触发方法(默认toString, hashcode, clone, equals),加载所有懒加载的属性。(全部加载)
(3)set方法,说明已经进行赋值,该属性不在需要懒加载。
(4)get方法,如果该属性属于懒加载属性,进行加载。(按需加载)
最后,执行父类的方法,也就是原来的对象的方法逻辑。
综上我们可以看到,其实不论是CglibProxyFactory还是JavassistProxyFactory,其实现懒加载的方式都是通过代理模式实现AOP的切面拦截,整体的代码逻辑是一样的,只不管CglibProxyFactory基于CGLIB,JavassistProxyFactory基于Javassist。