前言
在run方法【3】,也就是run方法中的:
prepareContext
方法中,我们知道了在load方法里,流程构建了一个BeanDefinitionLoader,来解析配置。
此处来专门讲讲这个类以及相关的BeanDefinition。
源码解析
先来看看这个类的注解:
Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a
simple facade over {@link AnnotatedBeanDefinitionReader},
{@link XmlBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}. See
{@link SpringApplication} for the types of sources that are supported.
注解很简短,说明了这个类实际上是
- AnnotatedBeanDefinitionReader
- XmlBeanDefinitionReader
- ClassPathBeanDefinitionScanner
的简单门面(simple facede)封装。
在构建的时候,这里会初始化所需的reader:
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
在上层构建传参的时候,这里的registry其实就是context强转了,sources是启动的main方法的入参,以及启动类。
在之前的解析中,我们到这一步就停止了:
void load() {
for (Object source : this.sources) {
load(source);
}
}
其实这里的load方法是个门面方法,对各种情况都做了考虑以及对应处理:
private void load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
load((Class<?>) source);
return;
}
if (source instanceof Resource) {
load((Resource) source);
return;
}
if (source instanceof Package) {
load((Package) source);
return;
}
if (source instanceof CharSequence) {
load((CharSequence) source);
return;
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
一般来说,这里的sources的内容是启动类,我们就看看对应的这个针对class的装载方法好了:
private void 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);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
}
if (isEligible(source)) {
this.annotatedReader.register(source);
}
}
这里我们SpringBoot启动并用不到Groovy,因此这里执行的是:
this.annotatedReader.register(source);
//
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
注解上说的很明确,BDLoader类确实就是一系列reader的门面,内部将source做了根据类型的对应处理。
doRegisterBean
接下来看看这个doRegisterBean:
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());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
1.创建BeanDefinition
此处来解析这部分代码:
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
static AnnotationMetadata introspect(Class<?> type) {
return StandardAnnotationMetadata.from(type);
}
static AnnotationMetadata from(Class<?> introspectedClass) {
return new StandardAnnotationMetadata(introspectedClass, true);
}
这里新建了一个AnnotatedGenericBeanDefinition。
这里出现了Spring中一个重要的组件:BeanDefinition。来看看这个类(AnnotatedGenericBeanDefinition)的继承关系,这样子也方便我们后续查找相关代码:
www.processon.com/view/link/6…
结合注解,这里就是新建了一个BD对象,这个BD对象实际上包含了class作为标识符,以及类所包含的注解。
-
这里有一个知识点:
metadata指的是元数据,这里是类的相关信息。
在类里面看,包括的是类相关信息,以及类包含的注解类的简略信息。
2.ABD属性解析与初步处理
这部分对应的代码为:
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
2.1 是否跳过bean注册
首先是判断是否应该跳过bean注册:
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
这里经过一系列特定规则的判断,来判断是否跳过bean注册。
- 这里需要注意的是,如果没有被@Conditional标注的类,是不能跳过的。
2.2 解析并获取相关信息
这部分对应代码如下:
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
supplier这里是null,根据名称应该是和ABD实例化bean相关的,后面有相关的再看看。
ScopeMetadata指的是bean对应的scope以及scope的代理行为的信息封装,在类的注释上描述得很详细了:
Describes scope characteristics for a Spring-managed bean including the scope
name and the scoped-proxy behavior.
The default scope is "singleton", and the default is to not create
scoped-proxies.
默认是scope=单例,行为是不创建scope代理。
接下来就是ABD设置bean的代理方式,并获取bean名称了。
2.3 处理BD
这部分对应代码如下:
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
//
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
这里就是对abd的一些注解,做了对应的处理:将对应的信息添加到ABD对象内;方法调用和内部的这些if做的事情都是相同的。
2.4 构建BD持有对象
这部分对应代码如下:
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
bdHolder其实就是通过名字(以及别名)持有了一个bd。
第二步就是通过上面获取的scopeMetadata,来创建代理。(如果采用的是默认的单例scope,那么这里就没有代理)
到了第三步,就是注册BD了,这也是这部分代码中最重要的逻辑,因此单独提取出来。
[重要] 注册bd
这部分对应代码如下:
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
//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);
}
}
}
在这里先看一下调用:
- 实际上如果标注了别名,那么会把这些别名,都绑定到这个beanName上。
记得上面传进来的registry是什么吗?实际上就是在run流程中使用到的context-AnnotationConfigServletWebServerApplicationContext,因此这里按照继承关系,找到的对应代码在
DefaultListableBeanFactory里面:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//1 - 验证部分代码
//2 - 更新map
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
1.验证
这里对应代码如下:
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
没什么好说的,就是验证,并让BD对自己的信息进行一下验证。
2.更新BDMap
对应代码如下,比较多,因此分成两块:
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果已有了
}
else {
//如果没有
}
//扫尾处理
这里的beanDefinitionMap也算是一个核心组件了
2.1 如果map中已有
这部分代码如下:
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
虽然代码较多,但看完实际上这里的逻辑不算复杂,就是对一些情况做了异常或日志的处理,最后更新了。
这里有一个小细节:
- 如果这里的BeanFactory,不允许bd重载(allowBeanDefinitionOverriding = false),就会抛异常。
2.2 如果没有
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
这里出现了一个关键的节点:hasBeanCreationStarted(),具体的判断逻辑是:
!this.alreadyCreated.isEmpty();
就涉及到了又一个关键的组件。但这里只做查找并不做更新,因此留到后面对BeanFactory的解释中再做研究。
这里实际上也很简单,如果bean的创建已经开始了:
- 那么此时为了维护迭代的稳定性,此时就把beanDefinition锁上,在方法内部做更新操作。
没有的话就一样,不锁,更新。
这里的frozenBeanDefinitionNames,一样不知道是啥东西,一样留到BeanFactory里再做深入研究。
2.3 扫尾处理
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
至此为止就更新完了对应的BD,最后为了维护类内部的稳定性,做了一些特定的处理,这些我们一样留到对BeanFactory的研究中再一探究竟。
总结
到这里就把对BeanDefinitionLoader以及BeanDefinition的源码大致看了一遍。
有几个核心的关键点:
- 对于BeanDefinitionLoader,实际上是一个多种解析方式的门面集合。
- BeanDefinition实际上对于Spring而言,类似于Bean的身份证信息,记录了类以及类相关注解的信息。