Mybatis-Plus (MP for short) is a Mybatis enhancement tool, so how is it enhanced? The fact is that it already encapsulates some CRUD methods, so development doesn’t need to write XML, just call these methods, similar to JPA. This article will look at the following implementation of MP to see how these enhancements are implemented.

Entrance class: MybatisSqlSessionFactoryBuilder

Through the entrance class MybatisSqlSessionFactoryBuilder# build method, the application starts up, the mybatis plus (MP) custom dynamic configuration XML file into mybatis.

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

There are two MP2 function classes involved

  • MybatisConfiguration extends MybatisConfiguration class inherited from Mybatis: MP dynamic script building, registration, and other logical judgments.

  • SqlRunnerInjector: MP XML script method that inserts some dynamic methods by default.

MybatisConfiguration class

Here we focus on the analysis of MybatisConfiguration class, in MybatisConfiguration, MP initializes its own MybatisMapperRegistry, MybatisMapperRegistry is the registry for MP to load custom SQL methods.

Many of the methods in MybatisConfiguration are implemented using the MybatisMapperRegistry rewrite

Three overloaded methods, addMapper, implement the function of registering MP dynamic scripts.

Public class MybatisConfiguration extends Configuration {/** * Mapper registration */ protected Final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this); / /... Public MybatisConfiguration() {super(); this.mapUnderscoreToCamelCase = true; languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class); } /** * MybatisPlus; SQL </p> * <p> 2. SQL </p> * <p> 3. XmlSql and SqlProvider cannot contain the same SQL </p> * <p> after adjustment SQL Priority: XmlSql > sqlProvider > CurdSql </p> */ @override public void addMappedStatement(MappedStatement ms) {//... } / /... /** * MybatisMapperRegistry */ @override public <T> void addMapper(Class<T> type) { mybatisMapperRegistry.addMapper(type); } / /... Omit several lines}Copy the code

In MybatisMapperRegistry, MP will mybatis MapperAnnotationBuilder replaced with MP own MybatisMapperAnnotationBuilder

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

In MybatisMapperRegistry addMapper method of a class, real MybatisMapperAnnotationBuilder into MP at the core of the class, MybatisMapperAnnotationBuilder this class is the key to achieve dynamic script MP classes.

MybatisMapperAnnotationBuilder dynamically constructed

Core classes in MP MybatisMapperAnnotationBuilder parser method, MP one traversal Mapper classes to be loaded, loaded method includes the following

public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder { @Override public void parse() { //... Omit several lines for (Method Method: Type.getMethods() {/** mybatis {Select @insert **/ parseStatement(method); InterceptorIgnoreHelper.initSqlParserInfoCache(cache, mapperName, method); SqlParserHelper.initSqlParserInfoCache(mapperName, method); } / * * this 2 lines of code, MP list into the default method * * / if (GlobalConfigUtils. IsSupperMapperChildren (configuration, type)) { GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type); } / /... Public void inspectInject(MapperBuilderAssistant builderAssistant, Class<? > mapperClass) { Class<? > modelClass = extractModelClass(mapperClass); / /... List<AbstractMethod> methodList = this.getMethodList(mapperClass); TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass); ForEach (m -> m.object (builderAssistant, mapperClass, modelClass, tableInfo)); mapperRegistryCache.add(className); } } public class DefaultSqlInjector extends AbstractSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<? > mapperClass) { return Stream.of( new Insert(), //... New SelectPage()).collect(toList()); }}Copy the code

In MybatisMapperAnnotationBuilder, MP real frame custom dynamic SQL statements to registration to Mybatis engine. AbstractMethod, on the other hand, implements SQL statement construction for concrete methods.

Concrete AbstractMethod instance classes that construct concrete method SQL statements

Take the SelectById class as an example

Public class extends AbstractMethod {@override public MappedStatement injectMappedStatement(Class<? > mapperClass, Class<? > < span style = "max-width: 100%; clear: both; <id="xyz"> **/ SqlMethod SqlMethod = sqlmethod. SELECT_BY_ID; SqlSource = new RawSqlSource(configuration, string.format (sqlmethod.getsQL (), sqlSelectColumns(tableInfo, false), tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(), tableInfo.getLogicDeleteSql(true, true)), Object.class); / * * will be added to the XML method method of mybatis MappedStatement * * / return enclosing addSelectMappedStatementForTable (mapperClass, getMethod(sqlMethod), sqlSource, tableInfo); }}Copy the code

Mybatis ${variable} #{variable} dynamic replacement and precompilation, has entered mybatis own function.

To summarize

MP rewrites and replaces more than ten classes of Mybatis in total, as shown in the following figure:

The increase of the overall, MP implementation mybatis means slightly complicated and not intuitive, but according to MybatisMapperAnnotationBuilder structural approach from the definition of the XML file, transform it into mybatis Resource resources, Mybatis class: SqlSessionFactoryBean

public class YourSqlSessionFactoryBean extends SqlSessionFactoryBean implements ApplicationContextAware { private Resource[] mapperLocations; @Override public void setMapperLocations(Resource... mapperLocations) { super.setMapperLocations(mapperLocations); MapperLocations = mapperLocations; /** mybatis = mapperLocations; } /** * {@inheritDoc} */ @Override public void afterPropertiesSet() throws Exception { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); /** Mybatis (mybatis, mybatis, mybatis, mybatis) So that you can achieve MP custom dynamic SQL and native SQL * * / this symbiotic relationship. SetMapperLocations (InjectMapper. GetMapperResource (enclosing dbType, the beanFactory, this.mapperLocations)); super.afterPropertiesSet(); }}Copy the code

In this article, the realization process of MP dynamic statement is briefly introduced, and a possible more convenient method is given.