mybatis扩展mybatis-plus原理剖析

发布于:2022-12-07 ⋅ 阅读:(283) ⋅ 点赞:(0)

一.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 factory.getObject();
}

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 sqlSessionFactory;
    }
}

3.XMLMapperBuilder.bindMapperForNamespace解析mapper.xml放入MybatisConfiguration对象

public class XMLMapperBuilder extends BaseBuilder {
  private void bindMapperForNamespace() {
      if (boundType != null && !configuration.hasMapper(boundType)) {
        configuration.addMapper(boundType);
      }
    }
}

4.MybatisConfiguration对象调用mybatisMapperRegistry注册对象

public class MybatisConfiguration extends Configuration { 
 public <T> void addMapper(Class<T> type) {
        mybatisMapperRegistry.addMapper(type);
    }
}

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 (!loadCompleted) {
                    knownMappers.remove(type);
                }
            }
        }
    }
}

6.MybatisMapperAnnotationBuilder.parserInjector解析注入

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

        }
  void parserInjector() {
        GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);
    }
}

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);
            }
        }
    }
}

 8.每个操作类,select,insert,delete,update调用MapperBuilderAssistant.addMappedStatement将包括sql在内的MappedStatement通过mappedStatements.put(ms.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) {
        mappedStatements.put(ms.getId(), ms);
    }
}

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: " + e, e);
        }
    }
}

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);   
  }
}

总结:

      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

本文含有隐藏内容,请 开通VIP 后查看