Mybatis-Plus由于其强大又简单的特性,被越来越多用于企业生产开发中,下面将Mybatis-Plus简称为MP
先简单看下其是如何使用的,假设已经新建了一张用户表,一个Spring Boot项目
① maven中引入MP的start jar包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
②在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹(路径修改成自己项目中的路径)
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(QuickStartApplication.class, args);
}
}
③编写bean,Mapper
用户Bean类略
Mapper类继承MP的BaseMapper
public interface UserMapper extends BaseMapper<User> {
}
④测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
这里没有写一句Sql,至于UserMapper.xml文件里面当然也是空的
那MP是如何实现的? 后面主要说下这个问题。
先看一下BaseMapper类,里面定义了一些CRUD方法,如果你搜索BaseMapper.xml,这个文件也是不存在的。
/**
public interface BaseMapper<T> {
/**
* 插入一条记录
* @param entity 实体对象
*/
int insert(T entity);
/**
* 根据 ID 删除
* @param id 主键ID
*/
int deleteById(Serializable id);
//其他省略..........
为了简化开发,我们都会使用自动注入的方式,而不会在Spring.xml中配置,更不会使用原始的在mybatis config xml中进行mapper映射配置
这是spring.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="cn.edu.nuc.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
因为我们配置了@MapperScan,Spring 会通过MapperScannerRegistrar类进行扫描注册Bean,Mapper类的工厂bean会在Spring AbstractApplicationContext类finishBeanFactoryInitialization方法中进行实例化,由于调用链较长,可以自己在MapperFactoryBean类checkDaoConfig中进行Debug
在checkDaoConfig方法中,会对Mapper类进行注册放入MybatisConfiguration(继承了Configuration)中
在MybatisMapperRegistry类(继承自MapperRegistry)的addMapper方法中调用MybatisMapperAnnotationBuilder的parse方法,在该方法中有这么一段代码。
//TODO 注入 CURD 动态 SQL (应该在注解之前注入)
if (GlobalConfigUtils.getSuperMapperClass(configuration).isAssignableFrom(type)) {
GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);
}
GlobalConfigUtils.getSqlInjector(configuration) 获取SQL注入器,如果没有指定,使用DefaultSqlInjector默认注入器,所有的注入器都继承自AbstractSqlInjector类
inspectInject方法中就会对CRUD等一些语句进行注入,并生成SqlSource
//循环注入
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
AbstractMethod.java
/**
* 注入自定义方法
*/
public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
this.configuration = builderAssistant.getConfiguration();
this.builderAssistant = builderAssistant;
this.languageDriver = configuration.getDefaultScriptingLanguageInstance();
/* 注入自定义方法 */
injectMappedStatement(mapperClass, modelClass, tableInfo);
}
injectMappedStatement是一个抽象方法会根据不同的method对象调用不同的injectMappedStatement方法
本例会调用SelectList类
public class SelectList extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
//获取selectList sql
SqlMethod sqlMethod = SqlMethod.SELECT_LIST;
//格式化Sql 语句
String sql = String.format(sqlMethod.getSql(), sqlSelectColumns(tableInfo, true),
tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo));
//创建SqlSource
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
//添加MappedStatement 到 Mybatis 容器
return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);
}
}
如上是Mp对selectList的一个加载过程,其他CRUD类似
后面具体执行的时候会通过MapperProxy动态代理Mapper接口,执行过程图如下,图较大
本文分享自微信公众号 - 阿提说说(itsaysay)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/2366888/blog/4554652