mybatis-spring启动流程源码

目录

前言

一、启动配置类

二、扫描Mapper接口,注册Bean定义

1.@MapperScan

2.MapperScannerConfigurer

三、实例化MapperFactoryBean

总结


前言

       在上一篇文章中分析了mybatis的启动流程,主要包括SqlSessionFactory的创建和configure配置文件的解析,然后是sqlSession的创建,最后完成了mapper动态代理对象的创建,本文主要分析在有spring参与的情况下,mybatis的启动流程。


一、启动配置类

        在mybatis-spring程序中,需要引入SqlSessionFactory这个bean,用于后面SqlSession的创建。

@Configuration
@ComponentScan("com.mybatis.spring.service")
@MapperScan(basePackages = "com.mybatis.spring.mapper")
@EnableTransactionManagement
public class MyBatisConfig {

  @Bean
  public DataSource dataSource(){
    Properties properties = new Properties();
    InputStream is = MyBatisConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
    try {
      // 加载配置文件
      properties.load(is);
    } catch (IOException e) {
      e.printStackTrace();
    }
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(properties.getProperty("jdbc.driver"));
    dataSource.setUrl(properties.getProperty("jdbc.url"));
    dataSource.setUsername(properties.getProperty("jdbc.username"));
    dataSource.setPassword(properties.getProperty("jdbc.password"));

    return dataSource;
  }


  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource());
//    factoryBean.setMapperLocations("classpath:mapper/*.xml");
    return factoryBean.getObject();
  }
  @Bean
  public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }

}

二、扫描Mapper接口,注册Bean定义

1.@MapperScan

       首先从MapperScan注解分析,可以看到这个注解引入了MapperScannerRegistrar类,最终注册了MapperScannerConfigurer类。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {}
  void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
    //将MapperScannerConfigurer注册到容器中,负责mapper接口的扫描
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }

2.MapperScannerConfigurer

       MapperScannerConfigurer主要实现了对mapper接口扫描,一般情况下,此时的SqlSessionFactory和SqlSessionTemplate都为空,如果在mapperScan注解中设置这些变量的值,就可以提前赋值。

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

         doScan方法首先通过父类方法将所有符合要求的类取出,此处重写了父类的isCandidateComponent方法,只会扫描包中的接口。

  public Set doScan(String... basePackages) {
    //将componentScan包下的接口都扫描出来,不需要添加@mapper注解,继承了isCandidateComponent方法,只扫描其中的接口
    Set beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
      LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
          + "' package. Please check your configuration.");
    } else {
      //处理扫描出来的接口,创建MapperFactoryBean,加入到容器中
      processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
  }

  protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
  }

        然后调用processBeanDefinitions方法,处理扫描出来的类,注册为MapperFactoryBean,并设置根据类型自动赋值,此处为SqlSession创建的关键。

  private void processBeanDefinitions(Set beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      //直接设置beandDefinition的类型是mapperFactoryBean类型,实例化时调用getObject方法,创建动态代理对象。
      definition.setBeanClass(this.mapperFactoryBeanClass);

      definition.getPropertyValues().add("addToConfig", this.addToConfig);

      boolean explicitFactoryUsed = false;

      if (!explicitFactoryUsed) {
        //设置属性注入为根据类型注入,在populateBean时会对属性自动赋值
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
      definition.setLazyInit(lazyInitialization);
    }
  }

三、实例化MapperFactoryBean

            在配置类中引入了SqlSessionFactory,会创建一个DefaultSqlSessionFactory。

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource());
//    factoryBean.setMapperLocations("classpath:mapper/*.xml");
    return factoryBean.getObject();
  }

        前面提到,MapperFactoryBean设置为根据类型自动注入,继承了SqlSessionDaoSupport,其中有一个属性为SqlSessionFactory,在populateBean的过程中,会调用该属性的set方法,却完成了对SqlSessionTemplate的赋值?????

         在加载MapperFactoryBean的过程中,将自动装配类型设置为按照类型装配,从而能够实现各种set方法的调用,如setSqlSessionFactory

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
      this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
    }
  }
  protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    return new SqlSessionTemplate(sqlSessionFactory);
  }

       MapperFactoryBean继承了DaoSupport,而DaoSupport又实现了InitializingBean接口,在bean实例化过程中,调用DaoSupport的afterPropertiesSet方法,然后调用MapperFactoryBean的checkDaoConfig方法,然后又调用了addMapper方法,实现了将接口中和对应xml文件中的方法及sql加入到mapperStatement中。

  protected void checkDaoConfig() {
    super.checkDaoConfig();

    notNull(this.mapperInterface, "Property 'mapperInterface' is required");

    Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
      try {
        //添加mapper接口对应的mapperStatement
        configuration.addMapper(this.mapperInterface);
      } catch (Exception e) {
        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
        throw new IllegalArgumentException(e);
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }

       MapperFactoryBean本身是FactoryBean,在调用getBean方法时会调用getObject方法,最终得到一个mapper的代理对象,关于代理对象的展开将在以后的文章中讲述。

  public T getObject() throws Exception {
    //调用的时候已经完成了整体configure,sqlSessionFactory,sqlsession的创建,然后获取mapper,构建动态代理
    return getSqlSession().getMapper(this.mapperInterface);
  }

总结

       本文主要讲述了在有spring参与的情况下,MapperFactoryBean的注册,属性注入和初始化过程中的一些重要节点,主要是SqlSessionFactory和SqlSession的创建,mapperStatement的生成,最后是mapper代理对象的创建,如有不足之处,还请大家指出。。

你可能感兴趣的:(mybatis,spring,spring,mybatis,java)