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