意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

mybatis扩展mybatis-plus原理剖析

来源:恒创科技 编辑:恒创科技编辑部
2024-01-29 19:20:59


一.mybatis-plus运行源码介绍1.MybatisPlusAutoConfiguration初始化SqlSessionFactory的bean,初始化参数,调用getObject方法
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
throws Exception {
// TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
return

mybatis扩展mybatis-plus原理剖析_java

2.MybatisSqlSessionFactoryBean工厂bean,生产SqlSessionFactory调用afterPropertiesSet,解析mapper.xml,放入自定义annotation的类对象xmlMapperBuilder.parse();
public class MybatisSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
final SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(targetConfiguration);
return

mybatis扩展mybatis-plus原理剖析_java_02


mybatis扩展mybatis-plus原理剖析

3.XMLMapperBuilder.bindMapperForNamespace解析mapper.xml放入MybatisConfiguration对象
public class XMLMapperBuilder extends BaseBuilder {
private void bindMapperForNamespace() {
if (boundType != null

mybatis扩展mybatis-plus原理剖析_mybatis-plus_03

4.MybatisConfiguration对象调用mybatisMapperRegistry注册对象
public class MybatisConfiguration extends Configuration { 
public <T> void addMapper(Class<T> type)

mybatis扩展mybatis-plus原理剖析_java_04

5.MybatisMapperRegistry调用MybatisMapperAnnotationBuilder组装自定义mapper放入配置对象,knownMappers.put(type, new MybatisMapperProxyFactory<>(type));
public class MybatisMapperRegistry extends MapperRegistry { 
@Override
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
boolean loadCompleted = false;
try {
knownMappers.put(type, new MybatisMapperProxyFactory<>(type));
MapperAnnotationBuilder
MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if

mybatis扩展mybatis-plus原理剖析_java_05

6.MybatisMapperAnnotationBuilder.parserInjector解析注入
public class MybatisMapperAnnotationBuilder extends 
MapperAnnotationBuilder {
@Override
public void parse() {
if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {
parserInjector();
}

}
void parserInjector()

mybatis扩展mybatis-plus原理剖析_源码_06

7.DefaultSqlInjector.inspectInject注入到配置,TableInfo tableInfo = TableInfoHelper.initTableInfo解析mapper接口类,初始化成tableInfo对象,方法inject循环注入
public abstract class AbstractSqlInjector implements ISqlInjector {
@Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
if (modelClass != null) {
if (!mapperRegistryCache.contains(className)) {
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo);
if (CollectionUtils.isNotEmpty(methodList)) {
// 循环注入自定义方法
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
} else {
logger.debug(mapperClass.toString() + ", No effective injection method was found.");
}
mapperRegistryCache.add(className);
}
}
}
}

mybatis扩展mybatis-plus原理剖析_mybatis-plus_07

mybatis扩展mybatis-plus原理剖析_源码_08

mybatis扩展mybatis-plus原理剖析_java_09

8.每个操作类,select,insert,delete,update调用MapperBuilderAssistant.addMappedStatement将包括sql在内的MappedStatement通过mappedStatements.put(getId(), ms)加入到MybatisConfiguration.mappedStatements
public class MybatisConfiguration extends Configuration {
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
@Override
public void addMappedStatement(MappedStatement ms)

mybatis扩展mybatis-plus原理剖析_java_10

9.SqlSessionTemplate.getMapper最终会调MybatisMapperRegistry.getMapper
public class MybatisMapperRegistry extends MapperRegistry {

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// TODO 这里换成 MybatisMapperProxyFactory 而不是 MapperProxyFactory
// fix https://github.com/baomidou/mybatis-plus/issues/4247
MybatisMapperProxyFactory<T> mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
mapperProxyFactory = (MybatisMapperProxyFactory<T>) knownMappers.entrySet().stream()
.filter(t -> t.getKey().getName().equals(type.getName())).findFirst().map(Map.Entry::getValue)
.orElseThrow(() -> new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry."));
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: "

mybatis扩展mybatis-plus原理剖析_java_11

10.MybatisMapperProxyFactory.newInstance调用jdk的动态代理生成mapper接口代理对象
public class MybatisMapperProxyFactory<T> {
@SuppressWarnings("unchecked")
protected T newInstance(MybatisMapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
}
}

mybatis扩展mybatis-plus原理剖析_mybatis-plus_12

总结:

1.mybatis-plus在mybatis的基础上通过解析mapper注解类的方式给mapper接口代理对象增加select,update,delete,insert,selectById等方法,查用简单方法无需再在mapper.xml中写sql

2.mybatis-plus逻辑删除,租户隔离,乐观锁,数据权限等操作是通过MybatisPlusInterceptor插件实现

3.集成点,在解析mapper.xml的时候,新建MybatisConfiguration继承configration,重写addMapper方法,新建MybatisMapperAnnotationBuilder继承MapperAnnotationBuilder,在parse注册自定义的MappedStatement

4.用户项目中如果有通用业务的查询,更新,添加或者删除可以仿照mybatis-plus的集成方式,添加自定义的MappedStatement


上一篇: API的魅力:H5让Web页面轻松控制多媒体音视频 下一篇: 手机怎么远程登录云服务器?