mybatis源码分析

Posted gsluofu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis源码分析相关的知识,希望对你有一定的参考价值。

说明:以下分析基于spring-framework-5.0.x,mybatis-spring-1.3.2,mybatis-3.4.6相关源码可自行去github下载或者maven依赖然后利用类似ideal工具自动关联源码功能。

我们知道spring对bean的管理,我们可以通过多种方式将bean添加进spring中进行管理其中包括:

  • 一般注解@Conponent、@Controller、@Service
  • @Import形式有三种:第一种用法:@Import({ 要导入的容器中的组件 } ):容器会自动注册这个组件,id默认是全类,第二种用法:ImportSelector:返回需要导入的组件的全类名数组,springboot底层用的特别多第三种用法:ImportBeanDefinitionRegistrar(如Mybatis和springboot整合时):手动注册bean到容器。
  • 当然也可以通过BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessor子类)进行bean注册。通过它的重写方法参数可以拿到register进而进行bean的注册或者
  • 使用beanRegister或者bean工厂

一:bean交由spring管理
mybatis通过@MapperScan标签完成对接口mapper的注入,我们依次点击@MapperScan->@Import(MapperScannerRegistrar.class)->MapperScannerRegistrar implements ImportBeanDefinitionRegistrar通过重写registerBeanDefinitions这个方法完成bean的注入。部分相关代码如下:

@Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    ...for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
     ...scanner.doScan(StringUtils.toStringArray(basePackages));
}
@Override
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    if (beanDefinitions.isEmpty()) {
      logger.warn("No MyBatis mapper was found in ‘" + Arrays.toString(basePackages) + "‘ package. Please check your configuration.");
    } else {
      processBeanDefinitions(beanDefinitions);
    }
    return beanDefinitions;
  }
 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
    ...
      // the mapper interface is the original class of the bean but, the actual class of the bean is MapperFactoryBean
      definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
      definition.setBeanClass(this.mapperFactoryBean.getClass());
}

二:MapperFactoryBean:MapperFactoryBean->SqlSessionDaoSupport->DaoSupport->InitializingBean(在bean实例化前执行checkDaoConfig方法)

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
  public MapperFactoryBean(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }//把接口类型传入factoryBean便于代理对象的产生
@Override
  protected void checkDaoConfig() {
    ...
        configuration.addMapper(this.mapperInterface)->mapperRegistry.addMapper(type)->parser.parse()(完成一些注解解析及sql生成等)
    ...
  }
}
@Override
  public T getObject() throws Exception {
    //getSqlSession()->SqlSessionTemplate 在MapperFactoryBean实例化过程中,会首先根据mybatis-spring-boot-autoconfigure中META-INF/spring.factories中的内容获取到MybatisAutoConfiguration这个配置类类名。在后续的bean创建过        程中,MybatisAutoConfiguration类的对象会被创建成一个继承了FactoryBean的代理对象放到bean工厂中 MybatisAutoConfiguration中SqlSessionTemplate sqlSessionFactory两个类的的生成是@Bean注解来生成
    return getSqlSession().getMapper(this.mapperInterface);->>>
       public T newInstance(SqlSession sqlSession) {
       final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
       return newInstance(mapperProxy);
      } 
  }
  }

public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   ...
        return method.invoke(this, args);
     ...
    return mapperMethod.execute(sqlSession, args);
  }
}
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
      Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      ...
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
       ...
  }
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    ...
      result = sqlSession.<E>selectList(command.getName(), param);
   ...
  }
//sqlSession为SqlSessionTemplate
@Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.sqlSessionProxy.<E> selectList(statement, parameter);//执行invoke方法
  }
private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
       ...
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);//mybatis结合spring时一级缓存失效原因
        }
      }
    }
  }

以上是关于mybatis源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段

Mybatis源码分析

MyBatis源码分析-IDEA新建MyBatis源码工程

MyBatis源码分析-IDEA新建MyBatis源码工程

MyBatis源码分析-MyBatis初始化流程

MyBatis源码分析-MyBatis初始化流程