How Mybatis-Plus Enhances MyBatis: A Deep Dive into Its Core Implementation

This article explains how Mybatis-Plus extends MyBatis by injecting dynamic configuration XML, customizing mapper registration, and generating CRUD SQL statements through classes like MybatisSqlSessionFactoryBuilder, MybatisConfiguration, MybatisMapperRegistry, and various AbstractMethod implementations.

Programmer DD
Programmer DD
Programmer DD
How Mybatis-Plus Enhances MyBatis: A Deep Dive into Its Core Implementation

Mybatis-Plus (MP) is an enhancement tool for MyBatis that provides ready‑made CRUD methods, eliminating the need to write XML mappings.

Entry class: MybatisSqlSessionFactoryBuilder

MP injects its dynamic configuration XML into MyBatis during application startup via the MybatisSqlSessionFactoryBuilder#build method.

public class MybatisSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
    public SqlSessionFactory build(Configuration configuration) {
        // ... omitted lines
        if (globalConfig.isEnableSqlRunner()) {
            new SqlRunnerInjector().inject(configuration);
        }
        // ... omitted lines
        return sqlSessionFactory;
    }
}

MybatisConfiguration class

MP extends MyBatis’s Configuration, creates its own MybatisMapperRegistry, and overrides methods to register custom mappers and SQL statements.

public class MybatisConfiguration extends Configuration {
    protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);
    // ...
    public MybatisConfiguration() {
        super();
        this.mapUnderscoreToCamelCase = true;
        languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class);
    }
    @Override
    public void addMappedStatement(MappedStatement ms) {
        // ...
    }
    @Override
    public <T> void addMapper(Class<T> type) {
        mybatisMapperRegistry.addMapper(type);
    }
    @Override
    public void addMapper(Class<?> type) {
        // use own MybatisMapperRegistry
    }
}

MybatisMapperRegistry

Replaces the default MapperAnnotationBuilder with MP’s MybatisMapperAnnotationBuilder.

public class MybatisMapperRegistry extends MapperRegistry {
    @Override
    public <T> void addMapper(Class<T> type) {
        // ... omitted lines
        MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
        parser.parse();
        // ... omitted lines
    }
}

MybatisMapperAnnotationBuilder

Parses mapper interfaces, registers methods annotated with @Select, @Insert, etc., and injects default method list when the mapper is a SuperMapper child.

public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
    @Override
    public void parse() {
        // ... omitted lines
        for (Method method : type.getMethods()) {
            parseStatement(method);
            InterceptorIgnoreHelper.initSqlParserInfoCache(cache, mapperName, method);
            SqlParserHelper.initSqlParserInfoCache(mapperName, method);
        }
        if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {
            GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);
        }
        // ... omitted lines
    }
    @Override
    public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
        Class<?> modelClass = extractModelClass(mapperClass);
        List<AbstractMethod> methodList = this.getMethodList(mapperClass);
        TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
        methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
        mapperRegistryCache.add(className);
    }
}

AbstractMethod implementations (example: SelectById)

Each concrete AbstractMethod builds the corresponding XML fragment and adds it to MyBatis’s MappedStatement.

/**
 * Query a single record by ID
 */
public class SelectById extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;
        SqlSource sqlSource = new RawSqlSource(configuration,
            String.format(sqlMethod.getSql(),
                sqlSelectColumns(tableInfo, false),
                tableInfo.getTableName(),
                tableInfo.getKeyColumn(),
                tableInfo.getKeyProperty(),
                tableInfo.getLogicDeleteSql(true, true)),
            Object.class);
        return this.addSelectMappedStatementForTable(mapperClass, getMethod(sqlMethod), sqlSource, tableInfo);
    }
}

Overall, MP rewrites more than ten MyBatis classes to provide dynamic SQL capabilities. A simpler approach is to generate the XML resources and inject them via a custom SqlSessionFactoryBean implementation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaMyBatisORMmybatis-plus
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.