目前Spring Boot已经逐渐取代原来基于xml配置的Spring,渐渐成为各大互联网或软件公司的主力框架。为了贴合实际应用,接下来主要以Spring Boot(本文使用1.5.7.RELEASE版本)为基础进行介绍。
invokeBeanFactoryPostProcessors()函数是在BeanFactory创建之后,Bean创建之前执行,作用是对已经创建的BeanFactory进行后续的操作。其中将Spring Boot中注解的Bean转换为BeanDefinition结构就在这里完成,BeanDefinition结构为之后创建Bean做准备。本文的主题便是探究Spring Boot如何注册BeanDefinition结构。
从类AbstractApplicationContext的refresh()函数中的invokeBeanFactoryPostProcessors()函数开始我们的主题。
invokeBeanFactoryPostProcessors(beanFactory);
进入到类PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors()函数。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()函数首先会“Invoke BeanDefinitionRegistryPostProcessors first, if any.”,接口BeanDefinitionRegistryPostProcessor的实现类用于注册BeanDefinition,这里传入的是ConfigurationClassPostProcessor对象处理被@Configuration注解的类。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
//...略去部分代码...
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
List priorityOrderedPostProcessors = new ArrayList();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registryPostProcessors.addAll(priorityOrderedPostProcessors);
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
//...略去部分代码...
}
invokeBeanDefinitionRegistryPostProcessors()函数。
invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
invokeBeanDefinitionRegistryPostProcessors()函数中的参数ConfigurationClassPostProcessor对象用于注册BeanDefinition。
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
执行类ConfigurationClassPostProcessor对象的postProcessBeanDefinitionRegistry()方法。
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
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);
processConfigBeanDefinitions(registry);
}
进入processConfigBeanDefinitions()函数。从函数名就可以看出这个函数是用于操作被@configuration注解的类。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//...略去部分代码...
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new LinkedHashSet(configCandidates);
Set alreadyParsed = new HashSet(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
//...略去部分代码...
}
首先创建了ConfigurationClassParser对象将被用于对被@configuration注解的类进行解析使用。
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
具体解析过程在函数parse()中。
parser.parse(candidates);
进入类ConfigurationClassParser的parse()函数,会看到依据被@configuration注解的类的BeanDefinition的类型选择不同的parse()函数。而if-else逻辑中的parse()函数都会执行processConfigurationClass()函数。
public void parse(Set configCandidates) {
this.deferredImportSelectors = new LinkedList();
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);
}
}
processDeferredImportSelectors();
}
protected final void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
protected final void parse(Class> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
processConfigurationClass()函数中继续调用doProcessConfigurationClass()函数。
如果变量sourceClass表示的类存在父类,doProcessConfigurationClass()函数会返回其父类,do-while循环执行。
我们程序中只有main()方法所在的类是@configuration注解的,而且无父类,当首次进入到processConfigurationClass()方法中,变量sourceClass就是我们自定义的有main()方法的入口类,do-while循环只执行一次。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//...略去部分代码...
// 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);
}
doProcessConfigurationClass()函数根据变量sourceClass表示的类,解析操作注解它的@ComponentScan注解、@Import注解和@ImportResource注解等。
这里看@ComponentScan注解的处理逻辑。此处存在着递归调用,递归以变量sourceClass为基础,如果扫描@ComponentScan注解描述的路径下其他类仍旧是被@configuration注解的,继续更深的扫描。doProcessConfigurationClass()->parse()->processConfigurationClass()>doProcessConfigurationClass()方法递归调用。
this.componentScanParser.parse()进行进一步处理。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
//...略去部分代码...
// Process any @ComponentScan annotations
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//处理@ComponentScan注解
Set 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) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(
holder.getBeanDefinition(), this.metadataReaderFactory)) {
//这里可能出现递归
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
//...略去部分代码...
}
进入类ComponentScanAnnotationParser中的parse()函数解析@ComponentScan注解相关的参数,例如excludeFilters,basePackages参数等。创建ClassPathBeanDefinitionScanner对象用于扫描@ComponentScan注解指定的包。
直接跳到函数最后一行scanner.doScan()。
public Set parse(AnnotationAttributes componentScan, final String declaringClass) {
//...略去部分代码...
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//...略去部分代码...
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
进入类ClassPathBeanDefinitionScanner中的方法doScan()。
类ClassPathBeanDefinitionScanner扫描参数basePackages指定包下所有定义的Bean,转换为BeanDefinition后进行注册。参数basePackages是根据@ComponentScan注解的参数进行解析获得的,如果没有在注解中设置,默认就是被@ComponentScan注解的类所在的包。所以我们要把有main()方法的入口类放在最外层的包中,这样就会扫描到我们定义的所有包下的Bean。
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet();
for (String basePackage : basePackages) {
//找到包路径下用户定义的Bean
Set candidates = findCandidateComponents(basePackage);
//循环依次注册BeanDefinition
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
doScan()方法中的findCandidateComponents()方法先找到参数basePackages路径下用户自定义的Bean,然后定义它们的BeanDefinition结构返回。
Set candidates = findCandidateComponents(basePackage);
doScan()方法中之后的for循环依次遍历Set
registerBeanDefinition(definitionHolder, this.registry);
自此Spring Boot完成了用户自定义Bean的BeanDefinition结构的注册。以后将使用BeanDefinition结构对Bean进行创建。