Mybatis源码解读:executor包(懒加载功能)
欢迎关注本人公众号:
1.懒加载功能的使用
要使用懒加载,需要在mybatis的配置文件中启用该功能。
<setting><setting name="lazyLoadingEnable" value="true"/></setting>
mybatis的懒加载的实现由executor包的loader子包支持。
2.懒加载功能的实现
2.1代理工厂
ProxyFactory是创建代理类的工厂接口,其中的setProperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置。createProxy方法用来创建一个代理对象
public interface ProxyFactory {
// 设置工厂属性 default void setProperties(Properties properties) {
} // 创建代理对象 Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);}
ProxyFactory接口有2个实现类,CglibProxyFactory和JavassistProxyFactor类。这两个实现类整体结构高度一致,内部类、方法设置都一样,只是实现原理不同。CglibProxyFactory基于cglib实现,JavassistProxyFactor基于javassist实现。
接下来以CglibProxyFactory类为源码进行分析:
CglibProxyFactory类中提供了两个创建代理对象的方法。其中createProxy方法重写了一个普通的代理对象,createDeserializationProxy方法用来创建一个反序列化的代理对象。
public class CglibProxyFactory implements ProxyFactory {
private static final String FINALIZE_METHOD = "finalize"; private static final String WRITE_REPLACE_METHOD = "writeReplace"; public CglibProxyFactory() {
try {
Resources.classForName("net.sf.cglib.proxy.Enhancer"); } catch (Throwable e) {
throw new IllegalStateException("Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.", e); } } // 创建一个代理 @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 Object createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
return EnhancedDeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); } private static class EnhancedResultObjectProxyImpl implements MethodInterceptor {
// 被代理类 private final Class<?> type; // 要懒加载的属性Map private final ResultLoaderMap lazyLoader; // 是否是激进懒加载 private final boolean aggressive; // 能够触发懒加载的方法名“equals”, “clone”, “hashCode”, “toString”。这四个方法名在Configuration中被初始化。 private final Set<String> lazyLoadTriggerMethods; // 对象工厂 private final ObjectFactory objectFactory; // 被代理类构造函数的参数类型列表 private final List<Class<?>> constructorArgTypes; // 被代理类构造函数的参数列表 private final List<Object> constructorArgs; 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; } 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; } /** * 代理类的拦截方法 * @param enhanced 代理对象本身 * @param method 被调用的方法 * @param args 每调用的方法的参数 * @param methodProxy 用来调用父类的代理 * @return 方法返回值 * @throws Throwable */ @Override public Object intercept(Object enhanced, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 取出被代理类中此次被调用的方法的名称 final String methodName = method.getName(); try {
synchronized (lazyLoader) { // 防止属性的并发加载 if (WRITE_REPLACE_METHOD.equals(methodName)) { // 被调用的是writeReplace方法 // 创建一个原始对象 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) { // 存在懒加载属性 // 则此时返回的信息要更多,不仅仅是原对象,还有相关的懒加载的设置等信息。因此使用CglibSerialStateHolder进行一次封装 return new CglibSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs); } else {
// 没有未懒加载的属性了,那直接返回原对象进行序列化 return original; } } else {
if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { // 存在懒加载属性且被调用的不是finalize方法 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); } } } } } // 触发被代理类的相应方法。能够进行到这里的是除去writeReplace方法外的方法,例如读写方法、toString方法等 return methodProxy.invokeSuper(enhanced, args); } catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t); } } } }
代理类最核心的方法是intercept方法,当被代理对象的其他方法被调用时,intercept方法的处理方式是:
- 如果设置了激进懒加载或者被调用的是触发全局加载的方法,则直接加载所有未加载的属性。
- 如果被调用的是属性写方法,则将该方法从懒加载列表中删除,因为此时数据库中的数据已经不是最新的,没有必要再去加载,然后进行属性的写入操作。
- 如果被调用的是读方法,则该属性尚未被懒加载的情况下,则加载该属性,如果该属性已经被懒加载过,则直接读取该属性。
3.ResultLoaderMap类
被代理对象可能会有多个属性可以被懒加载,这些尚未完成加载的属性是在ResultLoaderMap类的实例中存储的。ResultLoaderMap类主要就是一个map类,该类key为属性名的大写,value为LoadPair对象。LoadPair类是ResultLoaderMap类的内部类,它能实现对应属性的懒加载功能。
public static class LoadPair implements Serializable {
private static final long serialVersionUID = 20130412; // 用来根据反射得到数据库连接的方法名 private static final String FACTORY_METHOD = "getConfiguration"; // 判断是否经过了序列化的标志位,因为该属性被设置了transient,经过一次序列化和反序列化后会变为null private final transient Object serializationCheck = new Object(); // 输出结果对象的封装 private transient MetaObject metaResultObject; // 用以加载未加载属性的加载器 private transient ResultLoader resultLoader; // 日志记录器 private transient Log log; // 用来获取数据库连接的工厂 private Class<?> configurationFactory; // 未加载的属性的属性名 private String property; // 能够加载未加载属性的SQL的编号 private String mappedStatement; // 能够加载未加载属性的SQL的参数 private Serializable mappedParameter; private LoadPair(final String property, MetaObject metaResultObject, ResultLoader resultLoader) {
this.property = property; this.metaResultObject = metaResultObject; this.resultLoader = resultLoader; if (metaResultObject != null && metaResultObject.getOriginalObject() instanceof Serializable) {
final Object mappedStatementParameter = resultLoader.parameterObject; if (mappedStatementParameter instanceof Serializable) {
this.mappedStatement = resultLoader.mappedStatement.getId(); this.mappedParameter = (Serializable) mappedStatementParameter; this.configurationFactory = resultLoader.configuration.getConfigurationFactory(); } else {
Log log = this.getLogger(); if (log.isDebugEnabled()) {
log.debug("Property [" + this.property + "] of [" + metaResultObject.getOriginalObject().getClass() + "] cannot be loaded " + "after deserialization. Make sure it's loaded before serializing " + "forenamed object."); } } } } public void load() throws SQLException {
if (this.metaResultObject == null) {
throw new IllegalArgumentException("metaResultObject is null"); } if (this.resultLoader == null) {
throw new IllegalArgumentException("resultLoader is null"); } this.load(null); } /** * 进行加载操作 * @param userObject 需要被懒加载的对象(只有当this.metaResultObject == null || this.resultLoader == null才生效,否则会采用属性metaResultObject对应的对象) * @throws SQLException */ public void load(final Object userObject) throws SQLException {
if (this.metaResultObject == null || this.resultLoader == null) { // 输出结果对象的封装不存在或者输出结果加载器不存在 // 判断用以加载属性的对应的SQL语句存在 if (this.mappedParameter == null) {
throw new ExecutorException("Property [" + this.property + "] cannot be loaded because " + "required parameter of mapped statement [" + this.mappedStatement + "] is not serializable."); } final Configuration config = this.getConfiguration(); // 取出用来加载结果的SQL语句 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 + "]"); } // 创建结果对象的包装 this.metaResultObject = config.newMetaObject(userObject); // 创建结果加载器 this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter, metaResultObject.getSetterType(this.property), null, null); } // 只要经历过持久化,则可能在别的线程中了。为这次惰性加载创建的新线程ResultLoader if (this.serializationCheck == null) {
// 取出原来的ResultLoader中的必要信息,然后创建一个新的 // 这是因为load函数可能在不同的时间多次执行(第一次加载属性A,又过了好久加载属性B)。 // 而该对象的各种属性是跟随对象的,加载属性B时还保留着加载属性A时的状态,即ResultLoader是加载属性A时设置的 // 则此时ResultLoader中的Executor在ResultLoader中被替换成了一个能运行的Executor,而不是ClosedExecutor // 能运行的Executor的状态可能不是close,这将导致它被复用,从而引发多线程问题 // 是不是被两次执行的一个关键点就是有没有经过序列化,因为执行完后会被序列化并持久化 final ResultLoader old = this.resultLoader; this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement, old.parameterObject, old.targetType, old.cacheKey, old.boundSql); } this.metaResultObject.setValue(property, this.resultLoader.loadResult()); } private Configuration getConfiguration() {
if (this.configurationFactory == null) {
throw new ExecutorException("Cannot get Configuration as configuration factory was not set."); } Object configurationObject; try {
final Method factoryMethod = this.configurationFactory.getDeclaredMethod(FACTORY_METHOD); if (!Modifier.isStatic(factoryMethod.getModifiers())) {
throw new ExecutorException("Cannot get Configuration as factory method [" + this.configurationFactory + "]#[" + FACTORY_METHOD + "] is not static."); } if (!factoryMethod.isAccessible()) {
configurationObject = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
try {
factoryMethod.setAccessible(true); return factoryMethod.invoke(null); } finally {
factoryMethod.setAccessible(false); } }); } else {
configurationObject = factoryMethod.invoke(null); } } catch (final ExecutorException ex) {
throw ex; } catch (final NoSuchMethodException ex) {
throw new ExecutorException("Cannot get Configuration as factory class [" + this.configurationFactory + "] is missing factory method of name [" + FACTORY_METHOD + "].", ex); } catch (final PrivilegedActionException ex) {
throw new ExecutorException("Cannot get Configuration as factory method [" + this.configurationFactory + "]#[" + FACTORY_METHOD + "] threw an exception.", ex.getCause()); } catch (final Exception ex) {
throw new ExecutorException("Cannot get Configuration as factory method [" + this.configurationFactory + "]#[" + FACTORY_METHOD + "] threw an exception.", ex); } if (!(configurationObject instanceof Configuration)) {
throw new ExecutorException("Cannot get Configuration as factory method [" + this.configurationFactory + "]#[" + FACTORY_METHOD + "] didn't return [" + Configuration.class + "] but [" + (configurationObject == null ? "null" : configurationObject.getClass()) + "]."); } return Configuration.class.cast(configurationObject); } private Log getLogger() {
if (this.log == null) {
this.log = LogFactory.getLog(this.getClass()); } return this.log; } }
4.ResultLoader类
ResultLoader类是一个结果加载器类,它负责完成数据的加载工作。因为懒加载只涉及查询,而不需要支持增,删,改的工作,所以它只有一个查询方法selectList来进行数据的查询。
public class ResultLoader {
public Object loadResult() throws SQLException {
// 查询结果列表 List<Object> list = selectList(); // 把结果列表转化为指定对象 resultObject = resultExtractor.extractObjectFromList(list, targetType); return resultObject; } private <E> List<E> selectList() throws SQLException {
// 初始化ResultLoader时传入的执行器 Executor localExecutor = executor; if (Thread.currentThread().getId() != this.creatorThreadId || localExecutor.isClosed()) {
// 执行器关闭,或者执行器属于其他线程,则创建新的执行器 localExecutor = newExecutor(); } try {
// 查询结果 return localExecutor.query(mappedStatement, parameterObject, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, cacheKey, boundSql); } finally {
if (localExecutor != executor) {
localExecutor.close(false); } } }}
5.懒加载功能对序列化和反序列化的支持
如果要对查询结果进行序列化,实际上是对代理对象即EnhancedResultObjecctProxyImpl对象进行序列化,因为该类已经替换了被代理对象。为了保证懒加载操作支持序列化和反序列化,则必须保证在序列化时将被代理对象和代理对象的所有信息全都保存。所以在CglibProxyFactory中创建代理对象时,无论是创建EnhancedResultObjectProxyImpl类还是EnhancedDeserializationProxyImpl类,都会在它们的构造方法中调用createProxy方法。
// 创建一个代理 @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 Object createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
return EnhancedDeserializationProxyImpl.createProxy(target, unloadedProperties, objectFactory, constructorArgTypes, constructorArgs); } /** * 创建代理对象 * @param type 被代理对象类型 * @param callback 回调对象 * @param constructorArgTypes 构造方法参数类型列表 * @param constructorArgs 构造方法参数类型 * @return 代理对象 */ static Object crateProxy(Class<?> type, Callback callback, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Enhancer enhancer = new Enhancer(); enhancer.setCallback(callback); // 创建的是代理对象是原对象的子类 enhancer.setSuperclass(type); try {
// 获取类中的writeReplace方法 type.getDeclaredMethod(WRITE_REPLACE_METHOD); if (LogHolder.log.isDebugEnabled()) {
LogHolder.log.debug(WRITE_REPLACE_METHOD + " method was found on bean " + type + ", make sure it returns this"); } } catch (NoSuchMethodException e) {
// 如果没找到writeReplace方法,则设置代理类继承WriteReplaceInterface接口,该接口中有writeReplace方法 enhancer.setInterfaces(new Class[]{WriteReplaceInterface.class}); } catch (SecurityException e) {
// 什么都不做 } 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; }
createProxy方法中一个重要的操作是校验被代理类中是否含有writeReplace方法。如果被代理类没有该方法,则会让代理类继承WriteReplaceInterface获得一个writeReplace方法,因为该方法会在对象序列化前被调用,起到偷梁换柱的作用。
还没有评论,来说两句吧...