剖析springboot执行mybatis的SQL代码过程

springboot使用的是2.3.1

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


---------------------------------------

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
  • MapperScan说起

  创建数据源时会使用`@MapperScan`扫描相应包的路径

  MapperScan中有`@Import(MapperScannerRegistrar.class)`

  进入MapperScannerRegistrar

  `MapperScannerRegistrar`实现`ImportBeanDefinitionRegistrar`和`ResourceLoaderAware`

  观察`registerBeanDefinitions`中有一行代码

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);

  进入到MapperScannerConfigurer

  MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware

  其中实现了BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry用于注册Bean到Spring容器中

    /**
     * {@inheritDoc}
     *
     * @since 1.0.2
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      if (this.processPropertyPlaceHolders) {
        processPropertyPlaceHolders();
      }
  
      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
      scanner.setAddToConfig(this.addToConfig);
      scanner.setAnnotationClass(this.annotationClass);
      scanner.setMarkerInterface(this.markerInterface);
      scanner.setSqlSessionFactory(this.sqlSessionFactory);
      scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
      scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
      scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
      scanner.setResourceLoader(this.applicationContext);
      scanner.setBeanNameGenerator(this.nameGenerator);
      scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
      if (StringUtils.hasText(lazyInitialization)) {
        scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
      }
      scanner.registerFilters();
      scanner.scan(
          StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }

  重要的是`ClassPathMapperScanner继承自`ClassPathBeanDefinitionScanner`

  `ClassPathMapperScanner`的`scan()-->doScan()`调用`ClassPathBeanDefinitionScanner`的`doScan()`然后`ClassPathMapperScanner-->processBeanDefinitions()`用于创建`Set<BeanDefinitionHolder>`将bean定义信息注册到容器当中。

  接口本身是没有类的,那么这里将**MapperFactoryBean**类通过processBeanDefinitions方法设置进来,最终所有的dao层接口类都是这个**MapperFactoryBean**

  •  说一下MapperFactoryBean

  所有的sql信息执行都会通过这个类getObject(),就是sqlSession获取mapper的代理类,也就是各个接口的代理。

  当SpringBean容器初始化时候会调用到checkDaoConfig()。

  getSqlSession().getMapper(this.mapperInterface);,通过接口获取Mapper(代理类),调用过程如下;

  ​    \- DefaultSqlSession.getMapper(Class<T> type),获取Mapper

  ​    \- Configuration.getMapper(Class<T> type, SqlSession sqlSession),从配置中获取

  ​    \- MapperRegistry.getMapper(Class<T> type, SqlSession sqlSession),从注册中心获取到实例化生成

 

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
      final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
      if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
      }
      try {
        return mapperProxyFactory.newInstance(sqlSession);
      } catch (Exception e) {
        throw new BindingException("Error getting mapper instance. Cause: " + e, e);
      }
    }

  ​    \- mapperProxyFactory.newInstance(sqlSession);,通过反射工程生成MapperProxy

    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实现InvocationHandler,执行会调用invoke()-->final MapperMethod mapperMethod = cachedMapperMethod(method);

  mapperMethod.execute(sqlSession, args);执行SQL语句,并返回结果(INSERT、UPDATE、DELETE、SELECT)

  •  然后再从SqlSessionFactory说起

  先创建SqlSessionFactoryBean例如SqlSessionFactoryBean bean = new SqlSessionFactoryBean();

  SqlSessionFactoryBean实现了InitializingBean,所以实现了`afterPropertiesSet`

  this.sqlSessionFactory = buildSqlSessionFactory();

  buildSqlSessionFactory最后一行

this.sqlSessionFactoryBuilder.build(targetConfiguration);

  build方法

    public SqlSessionFactory build(Configuration config) {
      return new DefaultSqlSessionFactory(config);
    }

  所以是使用DefaultSqlSessionFactory创建sqlSessionFactory

 

  •  还有SqlSessionTemplate

  调用构造方法

this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());

  实现代码

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
        PersistenceExceptionTranslator exceptionTranslator) {
  
      notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
      notNull(executorType, "Property 'executorType' is required");
  
      this.sqlSessionFactory = sqlSessionFactory;
      this.executorType = executorType;
      this.exceptionTranslator = exceptionTranslator;
      this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
          new Class[] { SqlSession.class }, new SqlSessionInterceptor());
    }

  其中sqlSessionProxy是动态代理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值