目录
1. invokeBeanFactoryPostProcessors
2. MapperScannerRegistrar#registerBeanDefinitions
3. ClassPathMapperScanner#processBeanDefinitions
在Springboot项目中使用MyBatis往往会使用@MapperScan("package")注解。那么这个注解有什么用呢?本篇文章就从源码层面来分析该注解到底在弄啥。
点开@MapperScan注解会发现有一个@Import(MapperScannerRegistrar.class)注解。记住MapperScannerRegistrar.class这个类,待会儿会有用。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan
1. invokeBeanFactoryPostProcessors
让我们回顾Sping容器的启动流程。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
finally {
resetCommonCaches();
}
}
}
在refresh方法中(对应Springboot项目的org.springframework.boot.SpringApplication#refreshContext中的refresh方法)。invokeBeanFactoryPostProcessors方法《【四】Spring IoC 最全源码详解之 invokeBeanFactoryPostProcessors与ConfigurationClassPostProcessor扫包》一文中已经介绍了ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中的parser.parse(candidates)方法(如果读者不懂该步骤的作用和流程,强烈建议读者不要再往下读了。因为后面的你根本读不懂!)。
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
/// 本文介绍的起始点
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
.
(省略篇幅)
.
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
本文将从this.reader.loadBeanDefinitions(configClasses)开始重点介绍关于文章标题的事情。进入loadBeanDefinitions方法,
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
传入的configurationModel是parser.parse找到的所有配置类和用户自己写的类。大部分框架的配置类都在spring-boot-autoconfigure-2.1.1.RELEASE.jar包的org/springframework/boot/autoconfigure/*路径下。f