Mybatis源码---重写一个最简单的Mybatis架构实现(三)

   前两篇文章里,我们实现了一个简单的Mybatis。只要愿意,如果完善了后续的数据库操作,我们完全可以用它来替换本来的Mybatis。在本篇文章里,我们要做的是完成我们自定义Mybatis与Spring或SpringBoot集成时的自动配置。首先,我们在来熟悉一下在XML中配置MapperScannerConfigurer时的使用:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
  <property name="basePackage" value="com.mapper"/>
 </bean>

  在前面的文章里,我们详细分析过为Mapper接口生成代理的配置方法,这里不做过多描述。MapperScannerConfigurer类会为我们批量完成Mapper接口代理类的生成。看XML中的配置可以发现,需要为它注入一些属性。我们再来看看MapperScannerConfigurer类的源码中属性定义的部分:

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, 
 
InitializingBean, ApplicationContextAware, BeanNameAware {

  private String basePackage;

  private boolean addToConfig = true;
 
  private SqlSessionFactory sqlSessionFactory;

  private SqlSessionTemplate sqlSessionTemplate;

  private String sqlSessionFactoryBeanName;

  private String sqlSessionTemplateBeanName;

  private Class<? extends Annotation> annotationClass;

  private Class<?> markerInterface;

  private ApplicationContext applicationContext;

  private String beanName;

  private boolean processPropertyPlaceHolders;

  private BeanNameGenerator nameGenerator;

}

  从名称我们也可以大致猜出来它们的含义。需要重点说一下几个特别的属性:

  1. annotationClass是用来指定扫描哪个注解的。这样,MapperScannerConfigurer类只会为声明了该注解的类生成代理类。这样,就可以防止MapperScannerConfigurer把我们不需要生成代理类的类也生成代理类了。

  2.markerInterface是用来声明抽象Mapper接口的。比如,我们声明了一个所有Mapper接口都要继承的接口AbstractMapper,它本身并不需要被扫描,那么,就可以看设置为markerInterface来防止被扫描。 

    之所以要重点说明MapperScannerConfigurer类的属性含义,是因为在Mybatis被自动配置的时候,其实就是这些内容被自动设值了。Mybatis自动配置的关键是@MapperScan,可以看看它的源码:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {

  String[] value() default {};

  String[] basePackages() default {};

  Class<?>[] basePackageClasses() default {};

  Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

  Class<? extends Annotation> annotationClass() default Annotation.class;

  Class<?> markerInterface() default Class.class;

  String sqlSessionTemplateRef() default "";

  String sqlSessionFactoryRef() default "";

  Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

}

在@MapperScan注解中,我们发现它和MapperScannerConfigurer类的属性看起来很像。其实,这就是所谓默认配置了,Spring用注解中设置值的方式替代了XML中的属性注入。那么问题来了,@MapperScan的值是什么时候起作用的呢?我们发现@MapperScan注解的声明中有一行代码:@Import(MapperScannerRegistrar.class)。而@Import注解是用来引入@Configuration注解声明的内容的。这一切怎么解释呢?

我们看看@SpringBootApplication注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}

我们看到@SpringBootApplication注解声明时用到了@SpringBootConfiguration注解,那好,我们看看@SpringBootConfiguration注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

好了,我们明白了一件事,被@SpringBootApplication声明的类其实也被@Configuration注解声明了,被@SpringBootApplication注解声明的类其实就是主启动类了。前面的文章中提到过在主启动类其实执行了AbstractApplicationContext的run()方法(Spring容器启动的主要流程),代码如下:

public void refresh() throws BeansException, IllegalStateException {
            //刷新前的预处理
            prepareRefresh();

            // 获取BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // BeanFactory的预准备工作(BeanFactory进行一些设置)
            prepareBeanFactory(beanFactory);
           // BeanFactory准备工作完成后进行的后置处理工作,子类通过重写这个方法来在BeanFactory创建并预准备完成以后               做进一步的设置
            postProcessBeanFactory(beanFactory);

            // 执行BeanFactoryPostProcessor的后置处理方法
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册BeanPostProcessors,此时并不执行这些bean的后置处理器
            registerBeanPostProcessors(beanFactory);

             // 初始化MessageSource
             initMessageSource();

             // 初始化事件派发器
             initApplicationEventMulticaster();

             // 是一个空方法,留给容器的子类实现,子类重写这个方法,在容器刷新的时候可以自定义一些逻辑
             onRefresh();

             // 注册事件驱动
             registerListeners();

             //初始化所有剩下的单实例bean
             finishBeanFactoryInitialization(beanFactory);

             // 完成BeanFactory的初始化创建工作,IOC容器就创建完成
             finishRefresh();
    }

在执行其中的obtainFreshBeanFactory()方法时,关键代码如下:

DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
   this.beanFactory = beanFactory;
}

好了,重点来了。我们看看MapperScannerRegistrar 类的源码:

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  private ResourceLoader resourceLoader;

  /**
   * {@inheritDoc}
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    // this check is needed in Spring 3.1
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }

    Class<? extends Annotation> 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<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends MapperFactoryBean> 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<String> basePackages = new ArrayList<String>();
    for (String pkg : annoAttrs.getStringArray("value")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
    }
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

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

}

可以发现,大篇幅的代码都只描述了一个方法----registerBeanDefinitions()。本来还可以继续往下挖,但是呢,已经不是很有必要了吧?很明显可以猜出来,在SpringBoot主启动类启动时,会在加载BeanDefinition的阶段执行MapperScannerRegistrar类的registerBeanDefinitions()方法。这个方法比较简单,只要抓住ClassPathMapperScanner scan这条线索很容易就看懂了,和MapperScannerConfigurer类做的事情是一毛一样的。所以,我们只要定义一个类似@MapperScan的注解,然后把MapperScannerRegistrar类引入就可以了。

最后是福利时间,下面两段代码就是改造完成的MapperScannerRegistrar类和@MapperScan注解源码了,亲测可用。

@Component
public class FisherScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  private ResourceLoader resourceLoader;

  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(FisherScan.class.getName()));
    ClassPathFisherScanner scanner = new ClassPathFisherScanner(registry);

    // this check is needed in Spring 3.1
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }

    Class<? extends Annotation> 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<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends FisherFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!FisherFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setFisherFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }

    List<String> basePackages = new ArrayList<String>();
    for (String pkg : annoAttrs.getStringArray("value")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
    }
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

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

}

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FisherScannerRegistrar.class)
public @interface FisherScan {

  String[] value() default {};

  String[] basePackages() default {};

  Class<?>[] basePackageClasses() default {};

  Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

  Class<? extends Annotation> annotationClass() default Annotation.class;

  Class<?> markerInterface() default Class.class;

  Class<? extends FisherFactoryBean> factoryBean() default FisherFactoryBean.class;

}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值