mybatis源码解读之executor包懒加载功能

网友投稿 240 2022-08-28


mybatis源码解读之executor包懒加载功能

ProxyFactory是创建代理类的工厂接口,其中的setProperties方法用来对工厂进行属性设置,但是mybatis内置的两个实现类都没有实现该接口,所以不支持属性设置。createProxy方法用来创建一个代理对象

public interface ProxyFactory {

// 设置工厂属性

default void setProperties(Properties properties) {

}

// 创建代理对象

Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List 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> constructorArgTypes, List constructorArgs) {

return EnhancedResultObjectProxyImpl.createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);

}

// 创建一个反序列化的代理

public Object createDeserializationProxy(Object target, Map unloadedProperties, ObjectFactory objectFactory, List> constructorArgTypes, List 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 lazyLoadTriggerMethods;

// 对象工厂

private final ObjectFactory objectFactory;

// 被代理类构造函数的参数类型列表

private final List> constructorArgTypes;

// 被代理类构造函数的参数列表

private final List constructorArgs;

private EnhancedResultObjectProxyImpl(Class> type, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List> constructorArgTypes, List 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> constructorArgTypes, List 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方法的处理方式是:

如果设置了激进懒加载或者被调用的是触发全局加载的方法,则直接加载所有未加载的属性。

如果被调用的是属性写方法,则将该方法从懒加载列表中删除,因为此时数据库中的数据已经不是最新的,没有必要再去加载,然后进行属性的写入操作。

如果被调用的是读方法,则该属性尚未被懒加载的情况下,则加载该属性,如果该属性已经被懒加载过,则直接读取该属性。

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;

http://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) {

// 取出原来的ResultLoadehttp://r中的必要信息,然后创建一个新的

// 这是因为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.isAcceshttp://sible()) {

configurationObject = AccessController.doPrivileged((PrivilegedExceptionAction) () -> {

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;

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Flask模板abort方法、错误接收方法和设置响应头信息(import flask 报错)
下一篇:那些我们从牛客上学到的python干货(牛客网python测试考试答案)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~