Springboot整合Mybatis执行流程解析

377 阅读2分钟

整体执行流程

入口类为MybatisAutoConfiguration整体分为两步:

  1. 扫描@Mapper注解生成注解对应的BeanDefinition。
  2. 创建SqlSessionFactory工厂

整体执行流程如图:

Springboot+Mybatis执行Mapper逻辑流程图.png

主要的类

以下的类代码只关心核心逻辑,删去了if和catch等操作。

ClassPathMapperScanner

ClassPathMapperScanner 是扫描@Mapper注解的主要扫描类,scan()方法中会调用父类 ClassPathBeanDefinitionScanner#scan() 的方法在父类中注册扫描到的Mapper接口,然后在对 BeanDefinition 进行后置处理。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    // 省略其他方法和属性
    // Mapper接口的BeanClass类型
    private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;

    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {

        // 使用父类注册BeanDefinition
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
                // 打日志
        } else {
            //对BeanDefinition进行二次处理
            processBeanDefinitions(beanDefinitions);
        }
        return beanDefinitions;
    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        .........
        // 设置BeanDefinition的BeanClass
        definition.setBeanClass(this.mapperFactoryBeanClass);
        ........
    }

}

在生成该类并且进行扫描时,并没有开始创建SqlSessionFactory

Snipaste_2022-03-21_16-38-16.png

MapperFactoryBean

从上面的扫描类中可以看出BeanDefinition的BeanClass=MapperFactoryBean。

  1. extends SqlSessionDaoSupport ,为子类提供了 SqlSessionTemplate 的实例,子类可以通过 getSqlSession() 获取 SqlSessionTemplate
  2. implements FactoryBean<T> , getObject() 可以提供 @Mapper 接口对应的 MapperProxy 的实例。

结构如下:

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
  private Class<T> mapperInterface;
  public MapperFactoryBean() {
    // intentionally empty
  }
  
  public MapperFactoryBean(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }
  @Override
  public T getObject() throws Exception {
    // 这里调用了父类的方法得到了SqlSession
    return getSqlSession().getMapper(this.mapperInterface);
  }
}

/*******************************************************************/
  // 上述getMapper逻辑如下
  @Override
  public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
  }
  // 最后从MapperRegistry中得到了代理对象
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

MapperRegistry、MapperProxyFactory、MapperProxy

一句话:MapperRegistry缓存MapperProxyFactory,MapperProxyFactory创建MapperProxy

MapperRegistry 中存放着Mybatis解析mapper.xml时,namesapce对应的接口和 MapperProxyFactory 的缓存。

public class MapperRegistry {

    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }
    
    public <T> void addMapper(Class<T> type) {
      if (type.isInterface()) {
        boolean loadCompleted = false;
        knownMappers.put(type, new MapperProxyFactory<>(type));
        // 这里是对接口方法上的@Select、@Update注解做解析
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      }
    }
    // 针对Mapper创建代理类时最后会调用该方法
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        
        if (mapperProxyFactory == null) {
            //报错
        }
        // 只有获取Mapper的使用才会创建MapperProxy
        return mapperProxyFactory.newInstance(sqlSession);
    }
}

MapperProxyFactory 是创建接口代理的工厂类,结构如下

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  // 缓存接口中已经生成的代理方法
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
}

MapperProxy 对象作为最终的代理对象实现了动态代理接口


public class MapperProxy<T> implements InvocationHandler, Serializable {
    // 全部从MapperProxyFactory传入
    // 传入SqlSessionTemplate,最终执行SQL的对象
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethodInvoker> methodCache;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
      this.sqlSession = sqlSession;
      this.mapperInterface = mapperInterface;
      this.methodCache = methodCache;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
          return method.invoke(this, args);
        } else {
          return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
        }
    }

    private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
        MapperMethodInvoker invoker = methodCache.get(method);
        if (invoker != null) {
          return invoker;
        }
        return methodCache.computeIfAbsent(method, m -> {
          if (m.isDefault()) {
              // 处理接口中的default方法
          } else {
              // 再这里创建mapper.xml中指定的方法
            return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
          }
        });
    }