MyBatis-Plus 核心源码解析
自动配置类 MybatisPlusAutoConfiguration
MyBatis-Plus 的自动配置核心在于 MybatisPlusAutoConfiguration 类,其通过 Spring Boot 的自动配置机制初始化 SqlSessionFactory 实例:
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.typeHandlers)) {
factory.setTypeHandlers(this.typeHandlers);
}
Resource[] mapperLocations = this.properties.resolveMapperLocations();
if (!ObjectUtils.isEmpty(mapperLocations)) {
factory.setMapperLocations(mapperLocations);
}
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (!ObjectUtils.isEmpty(this.languageDrivers)) {
factory.setScriptingLanguageDrivers(this.languageDrivers);
}
Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver);
if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) {
factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());
}
GlobalConfig globalConfig = this.properties.getGlobalConfig();
getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler);
getBeanThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerator(i));
getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector);
getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator);
factory.setGlobalConfig(globalConfig);
return factory.getObject();
}
SQL 注入核心 AbstractSqlInjector
MyBatis-Plus 通过 AbstractSqlInjector 抽象类来完成 SQL 方法的注入。主要逻辑如下:
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
Class<?> modelClass = extractModelClass(mapperClass);
if (modelClass != null) {
String className = mapperClass.toString();
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
if (!mapperRegistryCache.contains(className)) {
List<AbstractMethod> methodList = getMethodList(mapperClass);
if (CollectionUtils.isNotEmpty(methodList)) {
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
} else {
logger.debug(mapperClass.toString() + ", 未发现有效注入方法。");
}
mapperRegistryCache.add(className);
}
}
}
执行器管理 MybatisConfiguration
MyBatis-Plus 中对 MyBatis 的执行器进行了扩展,支持多种执行策略:
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 MybatisBatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new MybatisReuseExecutor(this, transaction);
} else {
executor = new MybatisSimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new MybatisCachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
- SimpleExecutor:每次执行 SQL 都新建并关闭 Statement。
- ReuseExecutor:复用 Statement 对象,避免重复创建。
- BatchExecutor:批量执行 SQL,适合大批量更新操作。
- CachingExecutor:启用二级缓存,优先从缓存读取数据。
这些执行器的作用范围均限定在 SqlSession 生命周期内。
Mapper 动态代理 MybatisMapperProxy
MyBatis-Plus 使用 JDK 动态代理机制为 Mapper 接口生成代理对象:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (method.isDefault()) {
if (privateLookupInMethod == null) {
return invokeDefaultMethodJava8(proxy, method, args);
}
return invokeDefaultMethodJava9(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
MybatisMapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
SqlSession 模板 SqlSessionTemplate
为了线程安全地使用 SqlSession,MyBatis-Plus 提供了 SqlSessionTemplate,其内部通过代理拦截方法调用:
private class SqlSessionInterceptor implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(
sqlSessionFactory, executorType, exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, sqlSessionFactory)) {
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
if (exceptionTranslator != null && unwrapped instanceof PersistenceException) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
sqlSession = null;
Throwable translated = exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}
}