Mybatis源码解析之懒加载(二):ProxyFactory

版权声明:感谢您的阅读,欢迎讨论并指出不足,可自由转载,但请注明出处和作者 https://blog.csdn.net/qq_39470742/article/details/88814257

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。

猜你喜欢

转载自blog.csdn.net/qq_39470742/article/details/88814257