mybatis源码分析之mybatis使用到的设计模式
文章目录
理解设计模式的最好方法就是在实际框架代码中去学习,看别人是怎么实现的,以及在哪种场景中使用这种模式。mybatis源码中也使用了一些设计模式,把目前发现的模式做个记录:
创建型模式(Creational Patterns)
工厂方法模式(Factory Method pattern)
一对一的关系,一个工厂创建一个与其对应的对象,由子类实现创建对象的操作:
参考JdbcTransactionFactory和DefaultObjectFactory.create(),DefaultObjectFactory.create()代码实现如下:
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
建造者模式(Builder pattern)
创建的对象属性比较复杂,要分步骤处理,还是就是构造函数传的参数比较多的情况,对构造函数进行拆分,最后返回一个对象。
具体实现也可以不用抽象的Builder,视具体情况而定,可以参考ResultMap:
public ResultMap build() {
if (resultMap.id == null) {
throw new IllegalArgumentException("ResultMaps must have an id");
}
resultMap.mappedColumns = new HashSet<String>();
resultMap.idResultMappings = new ArrayList<ResultMapping>();
resultMap.constructorResultMappings = new ArrayList<ResultMapping>();
resultMap.propertyResultMappings = new ArrayList<ResultMapping>();
for (ResultMapping resultMapping : resultMap.resultMappings) {
//判断是内嵌查询还是内嵌结果集
resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null;
resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null);
final String column = resultMapping.getColumn();
if (column != null) {
//将内部标签属性为column的添加早已映射列
resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
} else if (resultMapping.isCompositeResult()) {
for (ResultMapping compositeResultMapping : resultMapping.getComposites()) {
final String compositeColumn = compositeResultMapping.getColumn();
if (compositeColumn != null) {
resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));
}
}
}
if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
resultMap.constructorResultMappings.add(resultMapping);
} else {
resultMap.propertyResultMappings.add(resultMapping);
}
if (resultMapping.getFlags().contains(ResultFlag.ID)) {
resultMap.idResultMappings.add(resultMapping);
}
}
if (resultMap.idResultMappings.isEmpty()) {
resultMap.idResultMappings.addAll(resultMap.resultMappings);
}
// lock down collections
resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);
return resultMap;
}
}
结构型模式(Structural Patterns)
组织各个独立的对象,形成一个更强大的对象。
装饰器模式(Decorator pattern)
通过传入的委派对象,去改变本身对象的责任与行为:
参考执行器CachingExecutor、以及缓存实现都用了装饰器模式,CachingExecutor就是一个装饰对象代码如下,通过构造函数传入委派对象Executor :
public class CachingExecutor implements Executor {
private static final Logger log = LoggerFactory.getLogger(CachingExecutor.class);
private Executor delegate;
private TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
......
}
动态代理模式(Proxy pattern)
由JDK的Proxy对象生成代理对象,运行期间动态执行目标方法。
参考MapperProxyFactory(相当于客户端)、MapperProxy(代理对象)、SqlSession(委派执行对象),MapperProxy执行源码:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//缓存真实调用方法,args为真实方法的参数
final MapperMethod mapperMethod = cachedMapperMethod(method);
log.debug("执行Mapper类中的方法");
return mapperMethod.execute(sqlSession, args);
}
此外mybatis的logging包下面的ConnectionLogger、PreparedStatementLogger、ResultSetLogger等都是动态代理对象。
参考资料:维基百科Creational pattern、Structural pattern、Behavioral pattern