Mybatis-Plus简单分析

半腔热情 提交于 2020-12-10 07:52:11

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源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!