Spring集成Mybatis源码分析(一)

Mybatis作为目前主流的数据库查询框架,他是如何集成在Spring当中的,可以给以后开发Spring扩展插件提供一个思路。

最近在学习Mybatis的源码,因此记录一下,以便以后再次学习。

首先Spring作为最流行的开发框架,所有程序员都可以去扩展,Mybatis就是利用了Spring的这些扩展点。

这里我就大致描述下Spring的执行过程

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
UserDao app = ac.getBean(UserDao.class);
System.out.println(app.qryIntfConfig("1"));

这是spring最原始的获取bean的方式,而所有单例的bean的初始化都在前3行代码里,Spring中会有许多的BeanDefinition,顾名思义,这些BeanDefinition就是用来描述一个bean的,比如bean是否是单例,bean的类型,bean的属性,bean的注入方式,bean的初始化方法等等。Spring定义有Bean工厂,工厂就是根据这些Bean的定义来实例化bean,而bean工厂有很多的后置处理器,其中包括Spring内置的以及程序员扩展的,而mybatis的集成就利用了spring的bean工厂后置处理器BeanDefinitionRegistryPostProcessor,这个类集成自BeanFactoryPostProcessor,关于bean工厂的后置处理器这就不细讲了,其中有个最重要的bean工厂后置处理器就是ConfigurationClassPostProcessor。

@MapperScan(value = "com.wugao.dao", annotationClass = Repository.class)
@Configuration
public class DataSourceConfig {

	@Bean()
	public BasicDataSource dataSource(){
		System.out.println("init datasource");
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.1)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=wbsdb)))");
		dataSource.setUsername("test");
		dataSource.setPassword("123456");
		dataSource.setDriverClassName(OracleDriver.class.getName());
		return dataSource;
	}

	@Bean
	public SqlSessionFactory sqlSessionFactory() throws Exception {
		System.out.println("init sqlSessionFactory");
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource());
		return sqlSessionFactoryBean.getObject();
	}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
    .....
}

要使用Mybatis首先我们需要开启扫描,本文主要讲解注解的扫描方式,@MapperScan,该注解需要指明扫描的包名,该注解中有另一个注解@Import(MapperScannerRegistrar.class),在Spring中注解被Import的类会被Spring内置的bean工厂后置处理器ConfigurationClassPostProcessor扫描到并注册成BeanDefinition,而MapperScannerRegistrar继承了ImportBeanDefinitionRegistrar类,该类的实现类的registerBeanDefinitions方法会在执行ConfigurationClassPostProcessor的后置处理器时被调用,具体方法如下,这个方法获取到MapperScanner中的属性,并且注册一个MapperScannerConfigurer的bean工程后置处理器,并把所有的MapperScan中的属性值添加到BeanDefinition的属性值中,以便后续实例化时使用。

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

  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
    
    // 创建一个BeanDefinitionBuilder用来产生BeanDefinition
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    builder.addPropertyValue("processPropertyPlaceHolders", true);

    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      builder.addPropertyValue("annotationClass", annotationClass);
    }

    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      builder.addPropertyValue("markerInterface", markerInterface);
    }

    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
    }

    String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
    if (StringUtils.hasText(sqlSessionTemplateRef)) {
      builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
    }

    String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
    if (StringUtils.hasText(sqlSessionFactoryRef)) {
      builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
    }

    List<String> 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()));

    String lazyInitialization = annoAttrs.getString("lazyInitialization");
    if (StringUtils.hasText(lazyInitialization)) {
      builder.addPropertyValue("lazyInitialization", lazyInitialization);
    }

    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

    // 注册BeanDefinition
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }

注册好的Mybatis后置处理器,会在ac.refresh()方法中的invokeBeanFactoryPostProcessors被执行,该方法会执行Mybatis后置处理器的postProcessBeanDefinitionRegistry方法。

// Invoke factory processors registered as beans in the context.
// 初始化了自定义的beanFactoryPostProcessors,放进了beanDifinitionMap
invokeBeanFactoryPostProcessors(beanFactory);
 @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,该类继承自Spring的ClassPathBeanDefinitionScanner类,这个类用来扫描指定条件的bean,如注解了@Component,@Configuration,@ComponentScan,@Import,@ImportResource的类,而Mybatis的ClassPathMapperScanner重写了他的部分方法registerFilters,isCandidateComponent,分别表示注册过滤器,以及过滤后扫除的bean是否满足一定条件

// 注册过滤器
public void registerFilters() {
    boolean acceptAllInterfaces = true;

    // 如果@MapperScan上指定了annotaionClass,那么表示注解了该注解的类会被扫描
    // 比如指定为Mapper.class,那么只有注解了@Mapper的类会接口会被扫描
    if (this.annotationClass != null) {
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

    // 指定了父接口的话,他的实现类会被扫描到
    if (this.markerInterface != null) {
      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
        @Override
        protected boolean matchClassName(String className) {
          return false;
        }
      });
      acceptAllInterfaces = false;
    }

    // 如果注解没有指明annotaionClass和markerInterface,默认扫描所有的类,接口
    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
    }

    // 排除package-info.java
    addExcludeFilter((metadataReader, metadataReaderFactory) -> {
      String className = metadataReader.getClassMetadata().getClassName();
      return className.endsWith("package-info");
    });
  }

// 如果扫出来的是接口并且不是内部类,则满足条件
@Override
  protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
  }

扫描出来的所有类会被注册为BeanDefinition,而此处有一个非常重要的操作,就是Mybatis将bean的class设置为了它自定义的MapperFactoryBean,这个类实现了FactoryBean,后续可以通过它的getObject产生一个实例。同时如果指定了sqlSessionFactoryBeanName或者sqlSessionTemplateBeanName,为其绑定属性,否则设置bean为自动装配,这里的自动装配会在bean初始化属性注入时会使用。

private void processBeanDefinitions(Set<BeanDefinitionHolder> 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
      definition.setBeanClass(this.mapperFactoryBeanClass);

      definition.getPropertyValues().add("addToConfig", this.addToConfig);
      // 是否指定了SqlSessionFactoryBeanName
      boolean explicitFactoryUsed = false;
      if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
        definition.getPropertyValues().add("sqlSessionFactory",
            new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
        explicitFactoryUsed = true;
      } else if (this.sqlSessionFactory != null) {
        definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
        explicitFactoryUsed = true;
      }

      if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
        if (explicitFactoryUsed) {
          LOGGER.warn(
              () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
        }
        definition.getPropertyValues().add("sqlSessionTemplate",
            new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
        explicitFactoryUsed = true;
      } else if (this.sqlSessionTemplate != null) {
        if (explicitFactoryUsed) {
          LOGGER.warn(
              () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
        }
        definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
        explicitFactoryUsed = true;
      }
      
      // 如果两者都没指定,使用自动注入方式
      if (!explicitFactoryUsed) {
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
      // 设置懒加载,默认为true
      definition.setLazyInit(lazyInitialization);
    }
  }

到这里,生成Mapper实例的BeanDefinition基本就生成了,后续在实例化及初始化过程中就会使用到这些BeanDefinition,里面包含了如何生成Maper的所有的信息,包括类,需要注入的SqlSessionFactory,注入方式等等,后面再写Mapper的实例化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值