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

xiaoxiao2025-04-19  20

   前两篇文章里,我们实现了一个简单的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; }

 

转载请注明原文地址: https://www.6miu.com/read-5028598.html

最新回复(0)