0%

mybatis 设计模式

MyBatis中设计模式

Builder模式

  • Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建
  • Mybatis中的SqlSessionFactoryBuilder有很多build方法,根据不同的参数可以创建不同的工厂

工厂模式

  • Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。

单例模式

  • 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
  • 在Mybatis中有两个地方用到单例模式,ErrorContext和LogFactory,其中ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息,而LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ErrorContext {
//通过ThrealLocal来保证线程安全
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal();
private ErrorContext() {
}

public static ErrorContext instance() {
ErrorContext context = (ErrorContext)LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}

return context;
}
}

代理模式

  • 当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理。
1
2
3
4
5
6
7
8
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}

组合模式

  • 识别组合模式的一个要点:实现了一个接口,又聚合了这个接口的集合,那么该类很有可能是组合模式中的组合对象;

img

  • 根节点接口
1
2
3
public interface SqlNode {
boolean apply(DynamicContext context);
}
  • 树结构中非叶子节点的抽象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MixedSqlNode implements SqlNode {
private List<SqlNode> contents;

public MixedSqlNode(List<SqlNode> contents) {
this.contents = contents;
}

@Override
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : contents) {
sqlNode.apply(context);
}
return true;
}
}

模板方法模式

  • 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。
  • 在Mybatis中,sqlSession的SQL执行,都是委托给Executor实现的,Executor包含以下结构:
  • img

适配器模式

  • 适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
  • 在Mybatsi的logging包中,有一个Log接口,该接口定义了Mybatis直接使用的日志方法,Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配。

装饰者模式

  • 装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),

迭代器模式

  • 迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
  • Mybatis的PropertyTokenizer是property包中的重量级类,该类会被reflection包中其他的类频繁的引用到。这个类实现了Iterator接口,在使用时经常被用到的是Iterator接口中的hasNext这个函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
private String name;
private final String indexedName;
private String index;
private final String children;

public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}

public String getName() {
return name;
}

public String getIndex() {
return index;
}

public String getIndexedName() {
return indexedName;
}

public String getChildren() {
return children;
}

@Override
public boolean hasNext() {
return children != null;
}

@Override
public PropertyTokenizer next() {
return new PropertyTokenizer(children);
}

@Override
public void remove() {
throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
}
}

委派模式

BaseExecutor的一个子类缓存执行器通过派遣选择其他三个执行器来执行