Spring源码中我已经知道的两种上下文: ClassPathXmlApplicationContext、AnnotationConfigApplicationContext
我们知道 Spring 启动的核心过程是通过 ApplicationContext#refresh 方法,加载 BeanDefinition 在 obtainFreshBeanFactory 方法中实现。
那么 SpringBoot
是在什么时候加载 BeanDefinition
?
其实SpringBoot
中,是通过@Configuration
注解来作为所有配置的入口标记的,例如上文中的例子,Application
类被添加了@SpringBootApplication
注解,而@SpringBootApplication
有被@SpringBootConfiguration
注解标记,而@SpringBootConfiguration
正是@Configuration
的子类。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
main 方法中调用了一个方法,即 SpringApplication#run
springboot 是如何加载 通过启动类上 @ComponentScan 注解指定的包路径来进行扫描,如果没有使用这个注解,会从启动类所在的包路径开始扫描。
springboot bean 创建过程包含的 SpringApplication run 方法中的 refresh方法。
整个加载顺序如下:
-SpringApplication#run()
--refreshContext(context)
---invokeBeanFactoryPostProcessors(beanFactory)
----ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
-----ConfigurationClassParser#parase
具体实现:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
关键看第 4 行 ConfigurableApplicationContext context = null
类型的声明。 然后通过 16 行 context = createApplicationContext();
创建了上下文,可以看下具体实现
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据当前的应用类型,获取正确的类名
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
// 实例化对象
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
在 createApplicationContext 方法中判断了应用环境选择对应的上下文类型,并且将其实例化。 选择了上下文,接下来就是刷新上下午 refreshContext.
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
image.png
我们找到了 ApplicationContext 的实现类,
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
看 refesh 中 invokeBeanFactoryPostProcessors
中
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
接着会发现 BeanDefinition 处理如下:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 为当前的BeanFactory生成一个id,防止同一个BeanFactory被重复处理
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
// 处理配置的BeanDefinitions
processConfigBeanDefinitions(registry);
}
继续看 processConfigBeanDefinitions(registry);
是如何处理 beanDefinition 的。
主要如下几个过程:
BeanDefinition
中找出有@Configuration
的类作为候选集BeanDefinition
BeanDefinition
被加载,需要判断其是否被@Configuration
标记,如果是则加入候选集具体代码如下: ConfigurationClassPostProcessor.class
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历当前容器中所有的BeanDefinition,从中寻找有@Configuration的类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 判断是否有@Configuration注解,如果有就加入候选列表
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果候选列表为空,就直接返回了
if (configCandidates.isEmpty()) {
return;
}
// 如果使用了@Order注解,就排个序
Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
@Override
public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet && sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
// 下面开始解析候选列表
// 创建一个ConfigurationClassParser,后面的解析将委托给这个对象
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
do {
//开始解析,细讲
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses =
new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// 如果BeanDefinitionReader为空,则创建一个,BeanDefinitionReader是用来加载BeanDefinition
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 前面ConfigurationClassParser#parse处理时遗留了三类类型,只将其解析并保存,并没有注册成BeanDefinition,在这个方法中进行处理
// 使用BeanDefinitionReader进行加载BeanDefinition,细讲
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 如果发现当前容器中的BeanDefinition数量比上一轮解析完以后的数量多,说明这一轮解析了新的BeanDefinition
// 这种情况需要对BeanDefinition列表逐个判断,如果其类型加了@Configuration注解,那么需要放入候选列表中,进行下一轮解析
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<String>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null) {
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
在解析和加载 BeanDefinition 时,需要通过特定的规则进行扫描, 主要看 ConfigurationClassParser#parse
和 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
两个方法。 看下 ConfigurationClassParser#parse
具体实现
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
// 依次解析所有候选BeanDefinition
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 处理前面在解析@Import注解中为DeferredImportSelector子类的对象
processDeferredImportSelectors();
}
根据不同的 BeanDefiniton 进行解析
image.png
继续深入看 parse 方法
protected final void parse(Class<?> clazz, String beanName) throws IOException {
this.processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 如果当前类使用了@Conditional注解,则需要根据条件判断是否要跳过该类的解析
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
//判断当前类是否已经解析过,防止重复解析
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
//如果是被@Import注解导入的,那么记录一下
existingClass.mergeImportedBy(configClass);
}
// 直接结束了,不需要重复解析
return;
} else {
// 如果当前类不是被其他类通过@Import注解导入的,说明其是被显式定义的(说明一个类被定义了两次),那么将旧的移除。(重新解析一次)
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
// 进行递归解析,直到该类没有父类为止,重头戏,细讲
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
ConditionEvaluator
类进行处理,这个类型是根据当前类的@Conditional
注解进行处理的。@Import
依赖的,那么记录一下就直接返回不重复处理了;如果不是被@Import
依赖的,那么就再解析一遍(覆盖上一次的解析结果)。doProcessConfigurationClass
方法进行处理,可以发现这个方法被一个循环所包围,因为方法的会返回当前类型的父类,如果其父类存在,则会循环解析,知道不存在父类时,会返回null
。那么看一下doProcessConfigurationClass
方法的实现, 这个具体处理 Configuration
的核心方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
// 递归处理当前类的内部类
processMemberClasses(configClass, sourceClass);
// 处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
// 解析PropertySource注解中的value字段,依次加载配置文件
processPropertySource(propertySource);
} else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 处理@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// @Conditional注解优先判断
for (AnnotationAttributes componentScan : componentScans) {
// 根据@ComponentScan中的参数进行扫描,实际上是委托给ClassPathBeanDefinitionScanner处理
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 如果新解析到的BeanDefinition使用了@Configuration,直接递归解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理@Import注解
processImports(configClass, sourceClass,
//提取出@Import注解需要导入的类型
getImports(sourceClass),
true);
// 处理@ImportResource注解
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
// 将配置的资源存起来,后面会统一处理
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 处理@Bean注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//解析添加了@Bean注解的放放,并存起来,后面统一处理
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 递归查询并处理接口中的@Bean注解
processInterfaces(configClass, sourceClass);
// 判断是否有父类,如果有父类,则返回,外层会递归调用;如果没有则返回null,结束解析
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
processMemberClasses
方法用来处理当前类的内部类,获取当前类的内部类,并循环递归调用processConfigurationClass
方法。
可以发现该方法的代码中,依次处理了配置类中所需要处理的五个注解。
@PropertySource
用来实现将指定的配置文件加载到当前Spring
环境中
@ComponentScan
的作用是自动扫描指定包中的所有类,并根据其是否有特定注解(例如@Service
、@Component
等)将其转化为BeanDefinition
加载当上下文中。
ComponentScan
注解处理方式是将注解中配置的包路径依次委托给ClassPathBeanDefinitionScanner
中进行处理, 如果解析到了新的BeanDefinition
且使用了@Configuration
注解,直接调用parse
方法进行递归解析。
@Import
可以将其他类引入当前上下文中,在该方法中,先通过getImports
方法解析需要导入的类型,再调用processImports
方法处理这些类型
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
//被导入的类型分为三类,依次处理
if (candidate.isAssignable(ImportSelector.class)) {
// 如果导入的是ImportSelector类型,则将其实例化,并调用其selectImports获取到真实需要导入的类名
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
// 如果是DeferredImportSelector的子类,就将其放入deferredImportSelectors中,延迟加载,后面会处理
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
} else {
// 非DeferredImportSelector子类,直接调用selectImports进行处理
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
// 如果导入的类型是ImportBeanDefinitionRegistrar的子类,实例化并调用其Aware接口,将这些实例存起来,后面会统一处理
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 即不是ImportSelector也不是ImportBeanDefinitionRegistrar的情况,当做有@Configuration注解的类处理,递归解析
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
在processImports
方法中,循环处理每个需要导入的类型,根据其类型分为三种处理方式:
如果导入的类实现了ImportSelector
接口:ImportSelector
是一个动态导入接口,可以实现其selectImports
方法,在该方法中根据条件返回最终需要导入的类。而在当前方法的实现则是会实例化这个ImportSelector
子类,调用其selectImports
方法获取需要导入的类型,并递归调用processImports
方法。
不过此处有个例外,如果导入类实现了DeferredImportSelector
接口,则不会在此处直接调用其selectImports
方法,而会延迟调用,在此处只是进行记录,具体调用时机会在后文中提到。
如果不是上述的两种接口的子类:将该类当做普通的@Configuration注解的类处理,递归解析。
使用@ImportResource
可以将xml
类型的配置导入并解析到当前项目中,但是在此处并没有真正进行解析,也将其暂存起来,在后面会统一处理。
@Bean
是通过注解方式进行Bean
定义最常用的方式,在此处扫描所有加了@Bean
注解的方法并将其暂存,后面统一处理。
对于通过@Import
导入的DeferredImportSelector
子类需要延迟处理,在该方法中进行加载,处理逻辑基本与处理ImportSelector
类似。
读者需要把思路重新回到ConfigurationClassBeanDefinitionReader#processConfigBeanDefinitions
方法中,前文我们已经把ConfigurationClassParser#parse
方法分析完了,接下来就是ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
方法。
这里调用的方法名称为loadBeanDefinitions
,直译过来就是加载BeanDefinition
,但其实根据上面的阅读可以发现,前面解析时已经加载了很多BeanDefinition
了,但是对于有些情况只做了记录,没有真正进行加载,而处理这些工作,正是ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
做的事情。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
// 再遍历一次候选类,加载之前未完成的工作
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
if (configClass.isImported()) {
// 如果当前类是被@Import进来的,那么当前类型需要注册成BeanDefinition
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//依次加载@Bean注解的方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 加载@ImportResource注解对应的资源
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 处理通过@Import导入的ImportBeanDefinitionRegistrar类型
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
@Import
引入的类自身注册成BeanDefinition
@Bean
注解的方法解析成BeanDefinition
并注册@ImportResource
依赖的配置文件@Import
导入的ImportBeanDefinitionRegistrar
类在此处处理其中配置文件的加载,是被委托给对应的BeanDefinitionReader
加载的,例如xml
文件被委托给XmlBeanDefinitionReader
处理,这个过程与传统的Spring
项目的启动时加载配置文件的过程是一样的。
对于ImportBeanDefinitionRegistrar
子类的处理过程是依次调用了其registerBeanDefinitions
方法,而其子类可以在这个方法中动态加载BeanDefinition
。