AnnotationConfigApplicationContext 源碼分析(二):注冊配置類
本文是作者的個人學(xué)習(xí)筆記缅叠,僅做參考肤粱,Spring代碼版本5.2.2
AnnotationConfigApplicationContext 源碼分析(一)
注冊配置類
注冊配置類將要解析由AnnotationConfigRegistry接口所提供的#register(Class<?>... componentClasses)方法领曼,該方法用于注冊一個或多個組件類(標注了@component的類)悯森,注意的是注冊完了之后容器必須調(diào)用#refresh()方法瓢姻,不然將會導(dǎo)致未知的問題幻碱。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
/**
* Register one or more component classes to be processed.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*
* 注冊一個或多個要處理的組件類褥傍。
* <p>請注意恍风,必須調(diào)用{@link #refresh()}朋贬,以便容器完全處理新類锦募。
* @param componentClasses 一個或多個組件類糠亩,例如赎线,{@link Configuration@Configuration}類
*/
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
}
根據(jù)代碼可以知道垂寥,實際上調(diào)用的是AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)方法
public class AnnotatedBeanDefinitionReader {
/**
* Register one or more component classes to be processed.
* <p>Calls to {@code register} are idempotent; adding the same
* component class more than once has no additional effect.
* @param componentClasses one or more component classes,
* e.g. {@link Configuration @Configuration} classes
*
* 注冊一個或多個要處理的組件類盏缤。
* <p>對{@code register}的調(diào)用是等冪的蓖扑;多次添加同一個組件類沒有額外的效果律杠。
* @param componentClasses 一個或多個組件類,例如{@link Configuration @Configuration}類
*/
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
}
for循環(huán)依次調(diào)用注冊組件類灰嫉,這里就不過多解析
public class AnnotatedBeanDefinitionReader {
/** **/
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param beanClass the class of the bean
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider, if any,
* in addition to qualifiers at the bean class level
* @param supplier a callback for creating an instance of the bean
* (may be {@code null})
* @param customizers one or more callbacks for customizing the factory's
* {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
*
* 從給定的bean類中注冊一個bean,從類聲明的注釋中派生其元數(shù)據(jù)股耽。
* @param beanClass 注冊的Bean的Class對象
* @param name bean的顯式名稱
* @param qualifiers 除了bean類級別的限定符之外物蝙,要考慮的特定限定符注釋(如果有的話)
* @param supplier 用于創(chuàng)建bean實例的回調(diào)(可以是{@code null})
* @param customizers 一個或多個回調(diào)册赛,用于自定義工廠的{@link BeanDefinition}震嫉,例如設(shè)置lazy init或primary標志
* @since 5.0
*/
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
//1柜砾、根據(jù)beanClass生成AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//2换衬、
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//3、supplier==null叫潦,略
abd.setInstanceSupplier(supplier);
//4官硝、解析BeanDefinition上的@Scope標簽,設(shè)置BeanDefinition的scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//5朋魔、解析BeanDefinition獲得beanName(Bean的名稱)
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//6、分析類上的多個注解害淤,在BeanDefinition上設(shè)置注解上設(shè)置的配置元數(shù)據(jù)
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//7窥摄、qualifiers==null崭放,略
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));
}
}
}
//8移国、customizers==null道伟,略
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
//9蜜徽、生成BeanDefinitionHolder對象
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//10砚蓬、作用域代理策略灰蛙,針對@Scope標簽的proxyMode屬性
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//11摩梧、注冊definitionHolder到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
往容器中注冊一個bean
參數(shù)解析:
- beanClass:解析的目標類
- name:這里為空,注冊的名字
- qualifiers:這里為空宣旱,暫不分析
- supplier:這里為空仅父,暫不分析
- customizers:這里為空,暫不分析
步驟:
- 生成AnnotatedGenericBeanDefinition對象(存儲Bean的描述信息的對象),持有beanClass笙纤,同時解析beanClass獲取部分配置元數(shù)據(jù)(配置元數(shù)據(jù)即描述這個Bean的配置信息)耗溜,存儲到該BeanDefinition對象中;
- 暫時跳過省容;
- 這里無作用抖拴,略;
- 使用scopeMetadataResolver解析BeanDefinition上的@Scope標簽蓉冈,確定作用域元數(shù)據(jù)城舞。然后設(shè)置到BeanDefinition上
- 解析BeanDefinition獲得beanName(Bean的名稱)
- 通過AnnotatedBeanDefinition上的配置元數(shù)據(jù)家夺,解析存儲在該配置元數(shù)據(jù)上的以下的注解信息煌茴,獲取注解上的值,存儲到該AnnotatedBeanDefinition對象上
- @Lazy
- @Primary
- @DependsOn
- @Role
- @Description
- 這里無作用,略;
- 這里無作用,略;
- 生成BeanDefinitionHolder對象,持有BeanDefinition和Bean的名稱
- 作用域代理策略,將根據(jù)參數(shù)判斷是否需要代理,使用jdk代理還是CGLIB代理
- 往容器中注冊BeanDefinitionHolder
生成AnnotatedGenericBeanDefinition對象
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class
* 為給定的bean類創(chuàng)建一個新的AnnotatedGenericBeanDefinition。
* @param beanClass 加載的bean類
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
}
這個類是GenericBeanDefinition(GenericBeanDefinition是通用的BeanDefinition)的基礎(chǔ)上實現(xiàn)AnnotatedBeanDefinition接口杉畜,該接口提供了用于暴露注解相關(guān)的配置元數(shù)據(jù),即AnnotationMetadata的接口。
AnnotatedGenericBeanDefinition類型的BeanDefinition通常只在注冊組件類的時候被定義软瞎。
步驟:
1. BeanDefinition持有類對象
2. 通過內(nèi)省(java機制)類對象生成StandardAnnotationMetadata對象(配置元數(shù)據(jù)對象)并被當前BeanDefinition持有。相關(guān)類將另起文章分析
解析BeanDefinition獲取ScopeMetadata
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
*
* <p>The exact type of annotation that is checked for is configurable via
* {@link #setScopeAnnotationType(Class)}.
* 默認情況下檢查bean類上是否存在Spring的{@link Scope@Scope}注釋的{@link ScopeMetadataResolver}實現(xiàn)。
* <p>檢查的注釋的確切類型可以通過{@link #setScopeAnnotationType(Class)}配置
*/
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
}
步驟:
- 新建ScopeMetadata對象
- 使用AnnotationConfigUtils工具類獲取標記了@Scope的注解對象(AnnotationAttributes)
- 如果注解對象不為空幻林,則解析注解對象的屬性整葡,并設(shè)置給配置ScopeMetadata(保存Scope注解信息的配置元數(shù)據(jù))
- value—>setScopeName
- proxyMode—>設(shè)置setScopedProxyMode:作用域代理模式俱萍,用于決定是否要代理這個類腥寇,代理的模式是jdk代理還是CGLIB代理
- 返回ScopeMetadata對象后,通過BeanDefinition#setScope(String scopeName)設(shè)置到BeanDefinition中持有
生成BeanName策略
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
}
BeanNameGenerator是Spring中為bean definitions生成名字策略接口。
AnnotationBeanNameGenerator生成BeanName的策略:
- 如果definition是AnnotatedBeanDefinition寥殖,則會通過解析類上的注解粤策,獲取以下注解(包括繼承的注解類)上value的值作為BeanName
- @Component
- @ManagedBean
- @Named
- 如果以上注解中value的值為null,將會獲取類名萍膛,轉(zhuǎn)化為beanName,轉(zhuǎn)換方式如下
- 常規(guī)類:package.MyConfiguration—>myConfiguration
- 靜態(tài)內(nèi)部類:package.MyConfiguration$Config—>myConfiguration.Config
作用域代理策略
public abstract class AnnotationConfigUtils {
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
}
如果代理模式為ScopedProxyMode.NO,則不做任何處理僻爽,否則進行ScopedProxyCreator#createScopedProxy方法返回一個新的BeanDefinitionHolder對象
獲取ScopedProxyFactoryBean類的BeanDefinitionHolder
final class ScopedProxyCreator {
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
}
public abstract class ScopedProxyUtils {
/**
* Generate a scoped proxy for the supplied target bean, registering the target
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
* @param definition the original bean definition
* @param registry the bean definition registry
* @param proxyTargetClass whether to create a target class proxy
* @return the scoped proxy definition
*
* 為提供的目標bean生成作用域代理,用內(nèi)部名稱注冊目標bean雁乡,并在作用域代理上設(shè)置“target bean name”扩淀。
*/
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
//targetBeanName = "scopedTarget."+ originalBeanName
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
// 為原始bean名稱創(chuàng)建一個作用域代理定義,
// 在內(nèi)部目標定義中“隱藏”目標bean菇曲。
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
// ScopedProxyFactoryBean的“proxyTargetClass”默認值為TRUE,因此不需要在這里顯式設(shè)置它酱固。
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
// 從原始bean定義復(fù)制autowire設(shè)置烁巫。
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
// 為了支持作用域代理,應(yīng)該忽略目標bean赛蔫。
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
// 在工廠中將目標bean注冊為單獨的bean鳄橘。
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
}
在上述過程中炸裆,主要做了三件事
- 新建一個ScopedProxyFactoryBean類的BeanDefinition,用于生成代理原來的Bean的代理Bean浪漠,設(shè)置所需的參數(shù),確定代理類使用jdk代理還是CGLIB代理律适。
- 處理原來的BeanDefinition
- 原來的BeanDefinition中autowireCandidate屬性和primary屬性設(shè)置為false
- 將原來的BeanDefinition的以("scopedTarget."+原BeanName)作為新名稱注冊到容器中
- 返回包含原BeanName和ScopedProxyFactoryBean類的BeanDefinition信息的BeanDefinitionHolder。
- 以后再調(diào)用原來的beanName去獲取bean的時候福荸,獲取的將是在ScopedProxyFactoryBean對象中獲取的BeanDefinition的代理對象。
總結(jié)
在注冊組件類的時候主要做了以下事情:
- 分析組件類生成BeanDefinition對象前域,將以下注解的配置元信息設(shè)置到BeanDefinition對象
- @Scope
- @Lazy
- @Primary
- @DependsOn
- @Role
- @Description
- 確定BeanName
- 根據(jù)@Scope的proxyMode屬性绢掰,進行不同的作用域代理策略
- 將組件類的BeanDefinition或ScopedProxyFactoryBean類的BeanDefinition注冊到容器中