spring启动时mybatis-plus注入sql源码解析

本文介绍了MyBatis-Plus在Spring启动时,对xxxMapper方法的分析及SQL语句处理过程。涉及Spring的InitializingBean接口,详细阐述了从MyBatisSqlSessionFactoryBean到MapperFactoryBean等一系列类的调用,最终将BaseMapper的方法注入到Configuration的mappedStatements中,并给出项目源码参考。

MP在spring启动就会挨个分析xxxMapper中的方法,并且将对应的SQL语句处理好,保存到configuration对象中的mappedStatements中。

 

首先,在contextApplication.xml文件中配置的sqlSessionFactory配置的是mybatisplus的MyBatisSqlSessionFactoryBean,其implements

ApplicationListener,

FactoryBean<SqlSessionFactory>,

InitializingBean

ssm启动信息

前置知识:

Spring的InitializingBean接口有很好的用处,位于spring beans中,它只提供一个方法afterPropertiesSet(),当你实现了该方法后,spring就会对你提供框架级的支持:当你通过sring容器生产出实现了该接口的类的实例后,它就会调用afterPropertiesSet方法,通过这个方法,你可以检查你的bean是否正确地被初始化了。

在com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean#afterPropertiesSet中

 

this.sqlSessionFactory = buildSqlSessionFactory();

 

在buildSqlSessionFactory方法中

final MybatisConfiguration targetConfiguration;
SqlSessionFactory sqlSessionFactory = this.sqlSessionFactoryBuilder.build(targetConfiguration);

初始化我们后面要使用的MybatisConfiguration

通过调用栈,可以看到,后面其执行了DaoSupport中的方法,DaoSupport也实现了InitializingBean,其afterPropertiesSet()方法中

checkDaoConfig();

最后执行的是MapperFactoryBean中的checkDaoConfig方法

Configuration configuration = getSqlSession().getConfiguration();
configuration.addMapper(this.mapperInterface);

 

在MyBatisConfiguration中

/**

 * 使用自己的 MybatisMapperRegistry

 */

@Override

public <T> void addMapper(Class<T> type) {

    mybatisMapperRegistry.addMapper(type);

}

 

其addMapper方法进入到mybatis-plus中 MyBatisMapperRegistry

之后执行

 

MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
parser.parse();

 

进入到MybatisMapperAnnotationBuilder中(这个是mybatis中的对象)

注意:在其构造函数中,构造了后面要使用的MapperBuilderAsssistant

this.assistant = new MapperBuilderAssistant(configuration, resource);

 

执行parse方法

GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);

返回DefaultSqlInjector,执行inspectInject方法

在AbstractSqlInjector中,得到methodList,逐个执行inject方法

List<AbstractMethod> methodList = this.getMethodList();
// 循环注入自定义方法

methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));

之后在AbstractMethod中执行inject方法,调用其抽象方法injectMappedStatement

/**

 * 注入自定义方法

 */

public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {

    /* 注入自定义方法 */

    injectMappedStatement(mapperClass, modelClass, tableInfo);

}

AbstractMethod的继承关系

抽象方法在子类中有不同的实现类

如方法是selectById,那么就会进入到SelectById子类中,调用其injectMappedStatement,准备好参数后,再调用AbstractMethod中的addMappedStatement方法

public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {

    SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;

    SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),

        sqlSelectColumns(tableInfo, false),

        tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),

        tableInfo.getLogicDeleteSql(true, false)), Object.class);

    return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);

}

SqlMethod : 枚举对象,MP支持的SQL方法

LOGIC_SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s} %s"),

 

TableInfo:数据库表反射信息,可以获取到数据库表相关的信息

 

其通过String.format来构造sql,包括sql语句及对应的表,列名,参数,主键列等,对应到%s上

String.format(sqlMethod.getSql(),

    sqlSelectColumns(tableInfo, false),

    tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),

    tableInfo.getLogicDeleteSql(true, false))

 

public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {

最后得到的sql:

<script>

INSERT INTO tbl_employee <trim prefix="(" suffix=")" suffixOverrides=",">

<if test="lastName != null">last_name,</if>

<if test="email != null">email,</if>

<if test="gender != null">gender,</if>

<if test="age != null">age,</if>

</trim> VALUES <trim prefix="(" suffix=")" suffixOverrides=",">

<if test="lastName != null">#{lastName},</if>

<if test="email != null">#{email},</if>

<if test="gender != null">#{gender},</if>

<if test="age != null">#{age},</if>

</trim>

</script>

 

构造出一个SqlSource

SqlSource: SQL语句处理对象

 

MapperBuilderAssistant:用于缓存、SQL参数、查询方法结果集处理等

通过MapperBuilderAssistant将每一个mappedStatement 添加到configuration中的mappedstatements中

MappedStatement statement = statementBuilder.build();

configuration.addMappedStatement(statement);

 

这个configuration为mybatis-plus的MyBatisConfiguration,调用其addMappedStatement方法

public void addMappedStatement(MappedStatement ms) {

    logger.debug("addMappedStatement: " + ms.getId());

    super.addMappedStatement(ms);

}

在这里打印日志

之后调用mybatis Configuration中的addMappedStatement方法,真正将方法添加到mappedStatements中

public void addMappedStatement(MappedStatement ms) {

  mappedStatements.put(ms.getId(), ms);

}

 

这样就在Configuration的mappedStatements中注入了这17个BaseMapper提供的方法

这个过程的流程图:

项目源码参考:https://gitee.com/constfafa/mybatis-plus-spring-demo.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值