介绍
在理解Bean的注册以及配置类是如何解析之前,有几个贯穿容器整个IOC特性的工具类需要先了解一下
1.BeanDefinition——spring bean的建模对象
那么什么是spring bean的建模对象呢?一言概之就是把一个bean实例化出来的模型对象?有人会问把一个bean实例化出来有Class就行了啊,Class也就是我们通常说的类对象,就是一个普通对象的建模对象,那么为什么spring不能用Class来建立bean呢?很简单,因为Class无法完成bean的抽象,比如bean的作用域,bean的注入模型,bean是否是懒加载等等信息,Class是无法抽象出来的,故而需要一个BeanDefinition类来抽象这些信息,以便于spring能够完美的实例化一个bean
上述文字可以简单理解spring当中的BeanDefinition就是java当中的Class
Class可以用来描述一个类的属性和方法等等其他信息
BeanDefintion可以描述springbean当中的scope、lazy,以及属性和方法等等其他信息
2.BeanDefinitionHolder
该类本质上还是一个BeanDefinition,然而它会比我们的BeanDefinition多一个beanName和alias属性,因为一个类注册到容器中首先这个类会被解析成BeanDefinition,然后会被put到一个beanDefinitionMap中,其中的key就是beanName,也就是在容器中对这个类的唯一标识名。
注意,BeanDefinition本身并不直接携带beanName,通常它的beanName由一个内置的BeanName生成器产生,所以如果我们需要依赖于beanName操作,那么我们需要在获取BeanDefinition时将其封装成BeanDefinitionHolder对象
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
...
}
3.BeanDefinitionReaderUtils
该类只有一个作用,那就是将一个BeanDefinitionHolder实例注册到容器中,也就是put到容器的beanDefinitionMap中
public abstract class BeanDefinitionReaderUtils {
...
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
...
4.AnnotatedBeanDefinitionReader
根据官方文档来看,这个类属于 ClassPathBeanDefinitionScanner的替代品, ClassPathBeanDefinitionScanner可以对目标路径下所有类进行批量加载注册,而AnnotatedBeanDefinitionReader则可以对一些单独的特别的被注解的类进行加载注册(某些类是动态生成的或是第三方交互时获得的,因此在扫描期间它们并不存在,需要手动进行读取)
该类依赖于前面提到的BeanDefinitionReaderUtils,同时依赖于ConditionEvaluator,后者是一个判断目标注解类是否符合自身标注的Conditional条件来决定是否跳过该类的注册和加载
public class AnnotatedBeanDefinitionReader {
private final BeanDefinitionRegistry registry;
private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private ConditionEvaluator conditionEvaluator;
...
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//判断该类是否符合注解条件
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//生成beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
...
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
5.BeanDefinitionLoader
前面提到的类都是关于类的注册,但是在注册之前,首先需要获取到类信息。因此该类的作用就是通过不同的数据源获取BeanDefinition实例,然后交由前面的AnnotatedBeanDefinitionReader完成注册
通过下面直接管关联的成员来看,BeanDefinitionLoader可以对注解类进行读取、对xml文件进行读取,对Resouce对象进行读取,同时还能够通过ClassPathBeanDefinitionScanner进行扫描读取,然后完成注册
class BeanDefinitionLoader {
private final Object[] sources;
private final AnnotatedBeanDefinitionReader annotatedReader;
private final XmlBeanDefinitionReader xmlReader;
private BeanDefinitionReader groovyReader;
private final ClassPathBeanDefinitionScanner scanner;
private ResourceLoader resourceLoader;
...
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
private int load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
load(loader);
}
if (isEligible(source)) {
this.annotatedReader.register(source);
return 1;
}
return 0;
}
....
}
6. ConfigurationClassParser
通过前面的几个类我们可以将配置源转化成BeanDefinition对象并完成注册,但这个时候,这些配置类中还隐藏着许多的注解类需要进行进一步的解析
ConfigurationClassParser是用来处理配置类的类,它将配置类中的各个注解成分解析出来,用一个ConfigurationClass封装,如果说BeanDefinition是对容器中的普通bean类进行的封装,那么ConfigurationClass就是专门对配置类的信息封装,通过这个类我们可以得到配置类中的所有标注了@Bean的方法集合以及其他实现了BeanDefinitionReader和ImportBeanDefinitionRegistrar等的类集合。这样我们就能够很容易的完成bean的注册
class ConfigurationClassParser {
...
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
//处理标注了Component的类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
processMemberClasses(configClass, sourceClass, filter);
}
// 处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("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)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
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)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// 处理@ImportResource注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
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) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !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;
}
...
}
7.ConfigurationClassBeanDefinitionReader
该类可以对解析好的ConfigurationClass对象进行处理,将其中需要注册到容器中的Bean注册到容器中
class ConfigurationClassBeanDefinitionReader {
...
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()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
...
}
8.ConfigurationClassPostProcessor
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,因此会在工厂后置处理器调用时执行,该类主要依赖于ConfigurationClassParser和ConfigurationClassBeanDefinitionReader,前者完成配置解析,后置完成Bean的注册
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
...
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
...
for (String beanName : candidateNames) {
...
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
...
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
...
}
while (!candidates.isEmpty());
...
}
配置类注册解析的流程
先附带一张流程图
(1) 在实例化容器时容器同时实例化了AnnotationBeanDefinitionReader和ClassPathBeanDefinitionScanner
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext{
...
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
...
}
(2) 在构造AnnotatedBeanDefinitionReader时,该类又通过AnnotationConfigUtils向容器中注册了一个ConfigurationClassPostProcessor工厂后置处理器
public class AnnotatedBeanDefinitionReader {
...
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
...
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
...
}
public abstract class AnnotationConfigUtils {
...
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
...
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
...
}
...
}
(3)完成容器实例化后,在SpringApplication的prepareContext方法中,SpringApplication将我们在一开始传入的配置类也就是@SpringBootApplication注解类注册到容器中
public class SpringApplication {
...
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
...
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
...
}
(4)容器准备完成后,会在refresh方法中调用工厂后置处理器对容器完成初始化,其中ConfigurationClassPostProcessor在调用时,会对容器的配置类进行解析,并将解析出的Bean对象著猜测到容器中
源码在上面ConfigurationClassPostProcessor的说明中