接着我們上次說的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)里的