mybatis 相关的源码详解笔记

初始化

现由此包进行初始化决议

1
2
3
4
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>

进而配置

1
2
3
4
5
6
7
Application启动类配置如下
@MapperScan("com.xxx.dao")

yaml中配置如下
mybatis:
mapperLocations: classpath:mapper/**/*.xml
typeAliasesPackage: com.ybxx.user.entity


初始化流程

@MapperScan主要@Import(MapperScannerRegistrar.class)
从而引出MapperScannerRegistrar去执行扫描basepackages任务
ClassPathMapperScanner继承ClassPathBeanDefinitionScanner作为主要执行扫描任务
扫描相关的类设置FactoryBeanmapperFactoryBean,后期直接从mapperFactoryBean#getObject获取相关的数据操作对象
并为这个mapperFactoryBean配置相关的SqlSessionFactory等配置项

MapperFactoryBean#getObject执行时,会引出getSqlSession().getMapper(this.mapperInterface);
从这引出MapperRegistry#getMapper从而又引出MapperProxyFactory.MapperProxy
代理类在执行invoke操作的时候引出MapperMethod(内部包裹SqlCommand[MapperStatement]和MethodSignature[ParamsResolver和ReturnSolver])
MapperMethod的SqlSession丢入SqlCommand#name(MapperStatement#id)并用MethodSignature的参数和返回解析整理

MapperInterface

ClassPathMapperScanner

MapperScannerConfigure&&MapperScannerRegistrar以上两个都用ClassPathMapperScanner的原理

它继承ClassPathBeanDefintionScanner,首先用了自己规则的registerFilters再父类的doScan获取到相关的beanDefinitions,
然后对beanDefinitions进行processBeanDefinitions处理

  • 对beanDefinition的构造函数第一个参数设置当前的className

    1
    definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
  • 设置当前的beanDefinition实例化类为MapperFactoryBean

    1
    definition.setBeanClass(this.mapperFactoryBean.getClass());
  • 给当前beanDefinition设置sqlSessionFactory

    1
    definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));

MapperFactoryBean

  • 该类每次先实例化把构造器的mapperInterface设置为上一个beanClassName

  • 实例化前先设置属性,此时建立好sqlSession

    1
    this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
  • 因为实现InitializingBean,所以每次getObject之前先afterPropertiesSet—->checkDaoConfig

    1
    2
    Configuration configuration = getSqlSession().getConfiguration();
    configuration.addMapper(this.mapperInterface);
  • 当别的类比如Service层userService中带MapperInterface依赖,populate则会引入MapperFactoryBean的getObject

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Override
    public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
    }


    public SqlSession getSqlSession() {
    return this.sqlSession;
    }

    public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
    }

    说白了就是从sqlSession引入configuration的mapperRegistry拿这个MapperInterface

MapperRegistry

由普通的getMapper引出MapperRegistry的MapperProxyFactory代理
从而MapperProxy代理引出MapperMethod

1
2
3
4
5
MapperRegistry#getMapper ----> MapperProxyFactory.MapperProxy     

MapperMethod ----> 内部有SqlCommand ----> 由之前设定的MapInterface转换相关的MappedStatement

MapperMethod ----> 内部还有MethodSignature, 参数转换(paramNameResolver),Return结果包装

接下来全部由MappedStatement#name(就是mapperStatement的id)去执行

MapperMethod方法内拿Sqlsession.select等方法传入MappedStatement#name

MapperProxyFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MapperRegistry {

private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

public MapperRegistry(Configuration config) {
this.config = config;
}

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}

......
}

MapperProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MapperProxy<T> implements InvocationHandler, Serializable {

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
}

MapperMethod

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
55
56
57
58
public class MapperMethod {

private final SqlCommand command;
private final MethodSignature method;

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}

public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}

......
}

SqlCommand

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

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}


private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {

//关键点从interface获取MapperStatement
String statementId = mapperInterface.getName() + "." + methodName;


if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}


执行流程

  • DefaultSqlSessionFactory工厂模式产DefaultSqlSession,并通过configuration生成executor以及配置信息传递给DefaultSqlSession

  • DefaultSqlSession#insert|update|delete|selectList|selectOne|selectMap|selectCursor由SqlSession引出以下实现类的各类操作

  • DefaultSqlSessionconfiguration#getMappedStatement根据ID获取具体的MappedStatement交给executor执行executor#update|query

  • executorCachingExecutor为基础,装饰器模式套(SimpleExecutor,ReuseExecutor,BatchExecutor其中一种)delegate执行executor#update|query

  • xxxExecutor#doQuery根据MappedStatementconfiguration,再根据MappedStatement执行configuration#newStatementHandler生成StatementHandler

    • StatementHandler划分为:PreparedStatementHandler,CallableStatementHandler,SimpleStatementHandler

    • xxxExecutor#prepareStatement间接执行了上层基础类BaseStatementHandler#prepare执行于各个子类instantiateStatement根据mappedStatement来执行connection.createStatement()创建不同的Statement

    • 最终在xxxExecutor中让其执行StatementHandler#query|update|queryCursor间接去执行statement.execute


基本组件

Builder

  • XMLConfigBuilder

    解析Config文件并添加到Configuration

  • XMLMapperBuilder

    解析Mapper文件并添加到Configuration

  • XMLStatementBuilder

    解析Mapper文件中的statement语句并添加到Configuration

Configuration总配置

DefaultSqlSession

默认的SqlSession

提供selectList,selectOne,insert,update,delete等方法

一般都有以下步骤

  • 1:MappedStatement从configuration取出
  • 2:executor去执行MappedStatement

到了executor有以下步骤

  • 1:有缓存取缓存,没有通过MappedStatement来转换成合适的StatementHandler
  • 2:StatementHandler通过prepareStatement转换合适的Statement
  • 3:Statement.query执行并包装结果

Executor

CachingExecutor
BaseExecutor:SimpleExecutor,BatchExecutor

以上三种为执行器,sqlSession要执行具体的sql;必须在要在这三种执行器中执行Statement

如果开启二级缓存(默认开启),CachingExecutor装饰器模式套(SimpleExecutor,BatchExecutor其中一种)delegate,
所以去query首先先中二级缓存,但是CachingExecutor没有createCacheKey所以交给delegate去createCacheKey,
然后拿key去找缓存没有则继续delegate去找

delegate都是BaseExecutor继承,query->queryFromDatabase->doQuery
queryFromDatabase会去找当前selSession的一级缓存,内部是一个HashMap

StatementHandler

PreparedStatementHandler, CallableStatementHandler, CallableStatementHandler

SimpleExecutor或BatchExecutor要拿以上三种StatementHandler去执行

1
2
3
4
5
6
7
8
9
10
11
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}

由MapperStatement转换而来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}

由RoutionStatementHandler静态代理一个delegate:PreparedStatementHandler, CallableStatementHandler, CallableStatementHandler三者之一

DefaultResultSetHandler

StatementHandler返回的结果包装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {

....
ResultSetWrapper rsw = getFirstResultSet(stmt);
.....

while (rsw != null && resultMapCount > resultSetCount) {
.....
handleResultSet(rsw, resultMap, multipleResults, null);
....
}
.....
}


private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
......
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}

typeAliases

一般在SqlSessionFactoryBean的变量设置了typeAliases,typeAliasesPackage这类变量,则直接configuration注册相关的alias

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
configuration.getTypeAliasRegistry().registerAlias(typeAlias);
//typeAliasRegistry.registerAlias

public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}

public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
TYPE_ALIASES.put(key, value);
}

否则就是在configuration.xml文件里利用XmlConfigBuilder#parse–>parseConfiguration
typeAliasesElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}

内部运用

TypeAliasRegistry在实例化会注册很多默认的别名映射类型
跟TypeHandlerRegistry一样,都会注册很多默认的Java类型映射数据库类型

用于XmlMapperBuilder中的cache,XmlStatementBuilder中的resultType,parameterType

typeHandler

跟typeAlias差不多,先从SqlSessionFactoryBean找,后从configuration.xml里面找
TypeHandlerRegistry初始化后会注册很多默认的Java类型映射数据库类型

1
2
3
XmlConfigBuilder#parse---->parseConfiguration--->typeHandlerElement

typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {

@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}

@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}

@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}

@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}

内部运用

主要运用resolveTypeHandler

1
resolveTypeHandler(javaTypeClass, typeHandler);

  • MapperBuilderAssistant#buildResultMapping
  • MapperBuilderAssistant#buildParameterMapping
1
2
3
4
5
public ResultMapping buildResultMapping(){
typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler)
....
return new ResultMapping.Builder()..typeHandler(typeHandlerInstance).build();
}

使用

于DefaultResultSetHandler最后包装结果的时候使用

plugins

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

包装点

1
2
3
4
5
6
7
8
9
10
11
12
13
XmlConfigBuilder#parseConfiguration----->pluginElement(root.evalNode("plugins"));

private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {

}
}

<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>

Plugin为InvocationHandler的jdk动态代理

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
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}

执行点

分别对应

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
Configuration类

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}

public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}

interceptorChain.pluginAll(executor)主要执行点

二级缓存

基础

Mybatis默认对二级缓存是关闭的,一级缓存默认开启,如果需要开启只需在mapper上加入配置就好了

缓存策略

  • 1.FIFOCache:先进先出算法回收策略

    装饰类,内部维护了一个队列,来保证FIFO,一旦超出指定的大小,则从队列中获取Key并从被包装的Cache中移除该键值对。

    1
    2
    3
    内部保留Deque双端队列  
    每次put的时候检测队列是否size过1024限制
    如果超过removeFirst,并把缓存也删除removeFirst的key
  • 2.LoggingCache:输出缓存命中的日志信息,如果开启了DEBUG模式,则会输出命中率日志。

  • 3.LruCache:最近最少使用算法

    1
    2
    3
    缓存回收策略,在内部保存一个LinkedHashMap默认size=1024并实现removeEldestEntry
    在size过大的时候拿出来最不使用的delestKey
    key和value都存key,每次put检测delestKey有则将delegate缓存也删除相同key
  • 4.ScheduledCache:定时1小时清空Cache,但是并没有开始一个定时任务,而是在使用Cache的时候,才去检查时间是否到了。

  • 5.SerializedCache:序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。
  • 6.SoftCache:基于软引用实现的缓存管理策略,软引用回收策略,软引用只有当内存不足时才会被垃圾收集器回收

    1
    SoftReference包裹,get的时候发现为null了则删除delegate缓存里面的内容
  • 7.SynchronizedCache:同步synchronized语法的缓存装饰器,用于防止多线程并发访问

  • 8.PerpetualCache 永久缓存,一旦存入就一直保持,内部就是一个HashMap
  • 9.WeakCache:基于弱引用实现的缓存管理策略
  • 10.TransactionalCache 事务缓存,一次性存入多个缓存,移除多个缓存
  • 11.BlockingCache 可阻塞的缓存,内部实现是ConcurrentHashMap

配置流程

SqlSessionFactoryBean 一个工厂bean,主要用于初始化SqlSession

由于是FactoryBean所以一切原由与getObject来初始化这个bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-settings.xml"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}


@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}

因为继承InitializingBean所以afterPropertiesSet会自动执行,但由于怕有些bean依赖于此提前getObject,所以设置了此方法
afterPropertiesSet引出buildSqlSessionFactory

主要buildSqlSessionFactory内部流程

  • XMLConfigBuilder(针对config.xml)
  • XmlMapperBuilder(针对mapper.xml,parameterMap|resultMap|sql)

    • XmlStatementBuilder(针对mapper.xml文件中select/update/delete/insert)负责构建MapperStatment
  • MapperBuilderAssistant辅助XmlMapperBuilder和XmlStatementBuilder来构建添加到configuration

    • buildParameterMapping
    • addParameterMap
    • buildResultMapping
    • addResultMap
    • getStatementParameterMap
    • getStatementResultMaps

包装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//这是遍历的,所以很多mapper.xml需要XMLMapperBuilder去解析
XMLMapperBuilder#configurationElement

//设定当前的命名空间
this.builderAssistant.setCurrentNamespace(namespace);

//解析parameterMap和resultMap
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));


这一部分的解析虽然利用了XmlMapperBuilder
其实间接性的利用了MapperBuilderAssistant#buildResultMapping---->addResultMap或者
MapperBuilderAssistant#buildParameterMapping--->addParameterMap
这里都是为了后期能够包装出MappedStatement而做的准备