Understanding the MyBatis‑Plus Mapper Method to SQL Mapping Process
This article explains how MyBatis‑Plus maps Mapper interface methods to executable SQL statements, detailing the auto‑configuration of SqlSessionFactory, XML parsing, mapper registration, SQL injection, and the dynamic proxy mechanism used at runtime.
MyBatis‑Plus is a powerful enhancement built on top of MyBatis that adds features such as optimistic‑lock plugins, automatic field filling, pagination, condition builders, and SQL injectors, allowing developers to work without XML mapper files by extending the BaseMapper interface.
1. Mapper method to SQL mapping – The auto‑configuration class MybatisPlusAutoConfiguration provides the sqlSessionFactory() method, which creates a MybatisSqlSessionFactoryBean (instead of the standard SqlSessionFactoryBean ) and returns a SqlSessionFactory instance. The relevant code is:
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// TODO use MybatisSqlSessionFactoryBean instead of SqlSessionFactoryBean
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
// ... additional component injection (key generator, sql injector, etc.)
factory.setGlobalConfig(globalConfig);
return factory.getObject();
}2. Building the SqlSessionFactory – The MybatisSqlSessionFactoryBean#buildSqlSessionFactory() method eventually calls MybatisSqlSessionFactoryBuilder#build() , which creates a MybatisXMLConfigBuilder to parse the XML configuration and mapper files, stores the parsed information in a targetConfiguration object, and finally builds a DefaultSqlSessionFactory :
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final MybatisConfiguration targetConfiguration;
MybatisXMLConfigBuilder xmlConfigBuilder = null;
// ... create and parse XML configuration
targetConfiguration = xmlConfigBuilder.getConfiguration();
// ... set environment, global config, etc.
SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(targetConfiguration);
return sqlSessionFactory;
}3. Parsing mapper XML – The MybatisXMLConfigBuilder#mapperElement() method collects classpath resources and mapper interfaces, then uses XMLMapperBuilder to parse each mapper XML file and registers the mapper classes with the configuration.
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
Set
resources = new HashSet<>();
Set
> mapperClasses = new HashSet<>();
setResource(parent, resources, mapperClasses);
for (String resource : resources) {
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
}
for (Class
mapper : mapperClasses) {
configuration.addMapper(mapper);
}
}
}4. Adding a mapper to the registry – MybatisConfiguration#addMapper() delegates to MybatisMapperRegistry#addMapper() , which creates a MybatisMapperAnnotationBuilder to parse annotations such as @Select and @Update on the mapper interface.
public
void addMapper(Class
type) {
if (type.isInterface()) {
if (hasMapper(type)) return;
knownMappers.put(type, new MybatisMapperProxyFactory<>(type));
MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
parser.parse();
}
}5. SQL injection for BaseMapper methods – The AbstractSqlInjector#inspectInject() method examines a mapper class, extracts its model class, obtains a list of AbstractMethod implementations, and injects the corresponding MappedStatement objects (e.g., SelectOne ) into the configuration.
public void inspectInject(MapperBuilderAssistant builderAssistant, Class
mapperClass) {
Class
modelClass = extractModelClass(mapperClass);
if (modelClass != null) {
List
methodList = getMethodList(mapperClass);
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
}
}6. Mapper scanning and bean registration – The @MapperScan annotation imports MapperScannerRegistrar , which registers a MapperScannerConfigurer . During container startup, MapperScannerConfigurer uses ClassPathMapperScanner#scan() to locate mapper interfaces and replaces their bean definitions with MapperFactoryBean definitions, enabling Spring to create mapper proxies.
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
// ... set properties such as basePackage, sqlSessionFactory, etc.
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}7. Autowiring and dynamic proxy execution – When a mapper is @Autowired, MapperFactoryBean#getObject() obtains the mapper via sqlSessionTemplate.getMapper() . The resulting MybatisMapperProxy implements InvocationHandler ; its invoke() method creates a MybatisMapperMethod for the called method and executes the prepared SqlSource to run the SQL.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
MybatisMapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}Through these steps, MyBatis‑Plus automatically transforms mapper interface methods into executable SQL statements, registers them in the MyBatis configuration, and provides a seamless, annotation‑driven data‑access layer for Java backend applications.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.