Mybatis的原理分析1(@Mapper是如何生效的)
接着我们上次说的SpringBoot自动加载原理。我们大概明白了在maven中引入mybatis后,这个模块是如下加载的。
可能会有人问了,一般我们的dao层都是通过Mapper接口+Mapper.xml的方式来操作数据库的,但是@Mapper注解并不是SpringBoot自带的注解,为什么加上@Mapper注解后这个接口就能够在项目中被各处注入使用了呢?
1:我们在maven中引入mybatis后就会自动加载 MybatisAutoConfiguration 这个类,它包含一个内部类 AutoConfiguredMapperScannerRegistrar,我们可以查看这个类的源码,部分如下:
1 public static class AutoConfiguredMapperScannerRegistrar 2 implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware { 3 4 private BeanFactory beanFactory; 5 6 private ResourceLoader resourceLoader; 7 8 @Override 9 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 10 11 logger.debug("Searching for mappers annotated with @Mapper"); 12 13 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); 14 15 try { 16 if (this.resourceLoader != null) { 17 scanner.setResourceLoader(this.resourceLoader); 18 } 19 20 List<String> packages = AutoConfigurationPackages.get(this.beanFactory); 21 if (logger.isDebugEnabled()) { 22 for (String pkg : packages) { 23 logger.debug("Using auto-configuration base package '{}'", pkg); 24 } 25 } 26 27 scanner.setAnnotationClass(Mapper.class); 28 scanner.registerFilters(); 29 scanner.doScan(StringUtils.toStringArray(packages)); 30 } catch (IllegalStateException ex) { 31 logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex); 32 } 33 }
我们会看到有个 registerBeanDefinitions() 方法。没错,这个方法就是那些被@Mapper标记的接口能被注入到SpringBoot的BeanFactory的关键。我们阅读这个方法,会发现有个 scanner.doScan(StringUtils.toStringArray(packages)),它是干嘛的,我们跳进去看一下,部分代码如下:
1 @Override 2 public Set<BeanDefinitionHolder> doScan(String... basePackages) { 3 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); 4 5 if (beanDefinitions.isEmpty()) { 6 logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); 7 } else { 8 processBeanDefinitions(beanDefinitions); 9 } 10 11 return beanDefinitions; 12 }
这个doScan方法调用了父类ClassPathBeanDefinitionScanner的doScan方法。这个类是Bean被注入BeanFactory的关键类,doScan方法是其中的关键方法,这里就不再分析。
那么通过这块,我们得到了哪些呢?
1:@Mapper注解的类是如何被注入到ApplicationContext(或者BeanFactory)里的