mybtis-springboot启动过程解析

mybtis-springboot启动过程解析

mybatis的启动

  • 重要配置

    • XML配置形式
    
    
        
        
        
        
        
        
    
    
    
    
        
        
        
        
    
    
  • Spring boot启动过程中,先加载mybatis的mapper/dao(实例化为spring的bean,初步加工)、再加载mybatis的mapper/dao配置文件、最后将mybatis的mapper对应的bean绑定到jdk的动态代理上的整个过程。如图所示

  • spring的启动过程,实际上就是AbstractApplicationContext.refresh()方法运行的过程,如图所示:
    mybtis-springboot启动过程解析_第1张图片

  • mapper实例化

    • mapper实例化就是将注解MapperScan指定的包下面的Dao接口实例化为spring的bean,这时的bean还没被彻底实例化,还不能使用。这个是在mybatis-spring包中实现的:
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  private ResourceLoader resourceLoader;

  /**
   * {@inheritDoc}
   */
  @Override
  public void setResourceLoader(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(mapperScanAttrs, registry);
    }
  }

  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    // this check is needed in Spring 3.1
    Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);

    Class annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      scanner.setAnnotationClass(annotationClass);
    }

    Class markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      scanner.setMarkerInterface(markerInterface);
    }

    Class generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }

    Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }

    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

    List basePackages = new ArrayList<>();
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value"))
            .filter(StringUtils::hasText)
            .collect(Collectors.toList()));

    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("basePackages"))
            .filter(StringUtils::hasText)
            .collect(Collectors.toList()));

    basePackages.addAll(
        Arrays.stream(annoAttrs.getClassArray("basePackageClasses"))
            .map(ClassUtils::getPackageName)
            .collect(Collectors.toList()));

    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

  /**
   * A {@link MapperScannerRegistrar} for {@link MapperScans}.
   * @since 2.0.0
   */
  static class RepeatingRegistrar extends MapperScannerRegistrar {
    /**
     * {@inheritDoc}
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
        BeanDefinitionRegistry registry) {
      AnnotationAttributes mapperScansAttrs = AnnotationAttributes
          .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScans.class.getName()));
      if (mapperScansAttrs != null) {
        Arrays.stream(mapperScansAttrs.getAnnotationArray("value"))
            .forEach(mapperScanAttrs -> registerBeanDefinitions(mapperScanAttrs, registry));
      }
    }
  }

}
- 接口ImportBeanDefinitionRegister的唯一方法registerBeanDefinitions就是根据指定的注解去注册bean,如图
        public interface ImportBeanDefinitionRegistrar {

        	/**
        	 * Register bean definitions as necessary based on the given annotation metadata of
        	 * the importing {@code @Configuration} class.
        	 * 

Note that {@link BeanDefinitionRegistryPostProcessor} types may not be * registered here, due to lifecycle constraints related to {@code @Configuration} * class processing. * @param importingClassMetadata annotation metadata of the importing class * @param registry current bean definition registry */ public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry); }

- 因此,在spring启动过程中,实现了接口ImportBeanDefinitionRegister的类会被调用其方法registerBeanDefinitions来注册额外的bean到BeanDefinitionRegistry中,这里就可以根据自己的需求,使用定制的注解来实例化bean
  • mapper配置文件加载
    -在springboot中,mapper配置文件的位置可以通过配置mybatis.mapperLocations来指定。MyBatisAutoConfiguration在实例化SqlSessionFactory的时候,就会去读取mybatis。mapperLocations指定的配置文件,然后解析里面的每个SQL。实例化SqlSessionFactory的代码在mybatis-spring-boot-autoconfigure包中,解析mapper.xml文件的代码位于mybatis中。
        @Bean
        @ConditionalOnMissingBean
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
            factory.setDataSource(dataSource);
            factory.setVfs(SpringBootVFS.class);
            if (StringUtils.hasText(this.properties.getConfigLocation())) {
                factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
            }
    
            org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
            if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
                configuration = new org.apache.ibatis.session.Configuration();
            }
    
            if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
                Iterator var4 = this.configurationCustomizers.iterator();
    
                while(var4.hasNext()) {
                    ConfigurationCustomizer customizer = (ConfigurationCustomizer)var4.next();
                    customizer.customize(configuration);
                }
            }
    
            factory.setConfiguration(configuration);
            if (this.properties.getConfigurationProperties() != null) {
                factory.setConfigurationProperties(this.properties.getConfigurationProperties());
            }
    
            if (!ObjectUtils.isEmpty(this.interceptors)) {
                factory.setPlugins(this.interceptors);
            }
    
            if (this.databaseIdProvider != null) {
                factory.setDatabaseIdProvider(this.databaseIdProvider);
            }
    
            if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
                factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
            }
    
            if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
                factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
            }
    
            if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
                factory.setMapperLocations(this.properties.resolveMapperLocations());
            }
    
            return factory.getObject();
        }
  • mapper bean与动态代理绑定
    • mapper对应的bean实例化最后一步,就是将接口和动态代理的类绑定。
    • MapperProxy就是具体的代理(MapperProxy源码在mybatis的binding模块中)
          protected T newInstance(MapperProxy mapperProxy) {
            return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
          }
        
          public T newInstance(SqlSession sqlSession) {
            final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
            return newInstance(mapperProxy);
          }
    ```**加粗样式**
    

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