首页 > 技术文章 > MyBatis-Plus源码分析

ruhuanxingyun 2021-03-23 12:31 原文

1. MybatisPlusAutoConfiguration自动配置类

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  // 注意是MybatisSqlSessionFactoryBean,而非SqlSessionFactoryBean
    MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    // mybatis配置文件位置
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
        factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }

    this.applyConfiguration(factory);
    // 指定外部化MyBatis Properties配置
    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);
    }

    // 别名包扫描路径,注册后在Mapper对应的XML文件中可以直接使用类名,而不用使用全限定的类名
    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
        factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
    }

    // 仅仅会扫描路径下以该类作为父类的域对象
    if (this.properties.getTypeAliasesSuperType() != null) {
        factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
    }

    // TypeHandler扫描路径
    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
        factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }

    if (!ObjectUtils.isEmpty(this.typeHandlers)) {
        factory.setTypeHandlers(this.typeHandlers);
    }

    // Mapper所对应的XML文件位置
    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 globalConfig = this.properties.getGlobalConfig();
    // 自动填充功能
    this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler);
    this.getBeanThen(IKeyGenerator.class, (i) -> {
        globalConfig.getDbConfig().setKeyGenerator(i);
    });
    // sql注入器
    this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector);
    // 自定义ID生成器
    this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator);
    factory.setGlobalConfig(globalConfig);
    // 获取SqlSessionFactory对象
    return factory.getObject();
}

2. AbstractSqlInjector抽象类,完成17个默认方法与SQL语句的转化

public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
    Class<?> modelClass = this.extractModelClass(mapperClass);
    if (modelClass != null) {
        String className = mapperClass.toString();
        Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
        if (!mapperRegistryCache.contains(className)) {
            List<AbstractMethod> methodList = this.getMethodList(mapperClass);
            if (CollectionUtils.isNotEmpty(methodList)) {
                TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
                // 循环注入自定义mapper
                methodList.forEach((m) -> {
                    m.inject(builderAssistant, mapperClass, modelClass, tableInfo);
                });
            } else {
                logger.debug(mapperClass.toString() + ", No effective injection method was found.");
            }

            mapperRegistryCache.add(className);
        }
    }

}

3. MybatisConfiguration类

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? this.defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Object executor;
    if (ExecutorType.BATCH == executorType) { // 批量执行器BatchExecutor
        executor = new MybatisBatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) { // 重用执行器ReuseExecutor
        executor = new MybatisReuseExecutor(this, transaction);
    } else { // 简单执行器SimpleExecutor(默认执行器)
        executor = new MybatisSimpleExecutor(this, transaction);
    }

    if (this.cacheEnabled) { // 缓存执行器
        executor = new MybatisCachingExecutor((Executor)executor);
    }

    Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
    return executor;
}

  A. simpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象;

  B. reuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用;

  C. batchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中,等待统一执行,它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理的;

  D. cachingExecutor:先从二级缓存中获取查询结果,存在就返回,不存在,再委托给Executor delegate去数据库取,delegate可以是上面任一的SimpleExecutor、ReuseExecutor、BatchExecutor;

  作用范围:四种执行器的作用范围都严格限制在SqlSession生命周期范围内。

4. MybatisMapperProxy类实现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 this.invokeDefaultMethodJava8(proxy, method, args);
            }

            return this.invokeDefaultMethodJava9(proxy, method, args);
        }
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }

    MybatisMapperMethod mapperMethod = this.cachedMapperMethod(method);
    return mapperMethod.execute(this.sqlSession, args);
}

 5. SqlSessionTemplate类

private class SqlSessionInterceptor implements InvocationHandler {
    private SqlSessionInterceptor() {
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);

        Object unwrapped;
        try {
            Object result = method.invoke(sqlSession, args);
            if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                sqlSession.commit(true);
            }

            unwrapped = result;
        } catch (Throwable var11) {
            unwrapped = ExceptionUtil.unwrapThrowable(var11);
            if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                sqlSession = null;
                Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
                if (translated != null) {
                    unwrapped = translated;
                }
            }

            throw (Throwable)unwrapped;
        } finally {
            if (sqlSession != null) {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }

        }

        return unwrapped;
    }
}

 

可参考:MyBatis Plus源码解析

推荐阅读