BeanDefinition在Spring初始化階段保存Bean的元數據信息,包括Class名稱、Scope、構造方法參數、屬性值等信息,本文將介紹一下BeanDefinition介面、重要的實現類,以及在Spring中的使用示例。 # BeanDefinition介面 用於描述了一個Bean實例, ...
BeanDefinition在Spring初始化階段保存Bean的元數據信息,包括Class名稱、Scope、構造方法參數、屬性值等信息,本文將介紹一下BeanDefinition介面、重要的實現類,以及在Spring中的使用示例。
BeanDefinition介面
用於描述了一個Bean實例,該Bean實例具有屬性、構造方法參數以及由具體實現提供的其他信息。
這是一個基礎介面:主要目的是允許BeanFactoryPostProcessor獲取和修改Bean實例屬性和其他元數據。
封裝以下信息:
- ParentName - The name of the parent definition of this bean definition.
- BeanClassName - The bean class name of this bean definition. The class name can be modified during bean factory post-processing, typically replacing the original class name with a parsed variant of it.
- Scope - Override the target scope of this bean, specifying a new scope name.
- isLazyInit - Whether this bean should be lazily initialized.
- DependsOn - The names of the beans that this bean depends on being initialized. The bean factory will guarantee that these beans get initialized first.
- AutowireCandidate - Whether this bean is a candidate for getting autowired into some other bean.
- Primary - Whether this bean is a primary autowire candidate.
- FactoryBeanName - The factory bean to use. This the name of the bean to call the specified factory method on.
- FactoryMethodName - Specify a factory method, if any. This method will be invoked with constructor arguments, or with no arguments if none are specified. The method will be invoked on the specified factory bean, if any, or otherwise as a static method on the local bean class.
- ConstructorArgumentValues - Constructor argument values for this bean.
- PropertyValues - The property values to be applied to a new instance of the bean.
- InitMethodName - The name of the initializer method.
- DestroyMethodName - The name of the destroy method.
- Role - The role hint for this BeanDefinition. The role hint provides the frameworks as well as tools an indication of the role and importance of a particular BeanDefinition.
- ResolvableType - A resolvable type for this bean definition, based on the bean class or other specific metadata.
- isSingleton - Whether this a Singleton, with a single, shared instance returned on all calls.
- isPrototype - Whether this a Prototype, with an independent instance returned for each call.
- isAbstract - Whether this bean is "abstract", that is, not meant to be instantiated.
- OriginatingBeanDefinition - The originating BeanDefinition.
AbstractBeanDefinition類
實現了BeanDefinition介面,具體的、完整的BeanDefinition基類,抽取出GenericBeanDefinition、RootBeanDefinition和ChildBeanDefinition的公共屬性。
擴展的屬性:
- AutowireMode - The autowire mode. This determines whether any automagical detection and setting of bean references will happen. Default is AUTOWIRE_NO which means there won't be convention-based autowiring by name or type (however, there may still be explicit annotation-driven autowiring).
- AUTOWIRE_NO
- AUTOWIRE_BY_NAME
- AUTOWIRE_BY_TYPE
- AUTOWIRE_CONSTRUCTOR
- AUTOWIRE_AUTODETECT
RootBeanDefinition類
繼承AbstractBeanDefinition類。
RootBeanDefinition表示在運行時支持BeanFactory中指定Bean的合併BeanDefinition。它可能是由多個相互繼承的原始BeanDefinition創建的,通常註冊為GenericBeanDefinitions。RootBeanDefinition本質上是運行時的"統一"RootBeanDefinition視圖。
RootBeanDefinition也可以用於在配置階段註冊各個BeanDefinition。然而,自Spring2.5以來,以編程方式註冊BeanDefinition的首選方式是GenericBeanDefinition類。GenericBeanDefinition的優勢是允許動態定義父依賴項,而不是將角色硬編碼為RootBeanDefinition。
擴展的屬性:
- DecoratedDefinition - Target definition that is being decorated by this bean definition.
- QualifiedElement - Specify the AnnotatedElement defining qualifiers, to be used instead of the target class or factory method.
- TargetType - Specify a generics-containing target type of this bean definition, if known in advance.
- stale - Determines if the definition needs to be re-merged.
- allowCaching
- isFactoryBean
GenericBeanDefinition類
繼承AbstractBeanDefinition類。
GenericBeanDefinition是用於構建標準BeanDefinition的一站式組件。與其他BeanDefinition一樣,它允許指定一個類以及可選的構造方法參數和屬性。另外,從父BeanDefinition派生可以通過parentName屬性靈活配置。
通常,使用GenericBeanDefinition類來註冊用戶可見的BeanDefinition,後置處理器可能會對其進行操作,甚至可能重新配置parentName屬性。如果父子關係恰好是預先確定的,請使用RootBeanDefinition和ChildBeanDefinition。
AnnotatedBeanDefinition介面
繼承BeanDefinition介面。
擴展BeanDefinition介面,提供Bean的AnnotationMetadata,而不需要載入該類。
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
*/
MethodMetadata getFactoryMethodMetadata();
}
ScannedGenericBeanDefinition類
GenericBeanDefinition類的擴展,基於ASM ClassReader,實現了AnnotatedBeanDefinition介面,可以獲取註解元數據。
這個類不會提前載入Bean Class。它從.class文件檢索所有相關的元數據,並使用ASM ClassReader進行解析。
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
/**
* Create a new ScannedGenericBeanDefinition for the class that the
* given MetadataReader describes.
* @param metadataReader the MetadataReader for the scanned target class
*/
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
public MethodMetadata getFactoryMethodMetadata() {
return null;
}
}
AnnotatedGenericBeanDefinition類
GenericBeanDefinition類的擴展,實現了AnnotatedBeanDefinition介面,可以獲取註解元數據。
public class AnnotatedGenericBeanDefinition
extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
private MethodMetadata factoryMethodMetadata;
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
} else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
public AnnotatedGenericBeanDefinition(
AnnotationMetadata metadata,
MethodMetadata factoryMethodMetadata) {
this(metadata);
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
Spring中使用BeanDefinition示例
註冊componentClasses
AnnotationConfigApplicationContext啟動代碼:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ServiceConfig.class);
applicationContext.refresh();
AnnotationConfigApplicationContext在啟動時可以使用register方法註冊@Configuration類,本小節將從這個方法入手看一個BeanDefinition的使用示例:
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
// reader.register(...)
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
private <T> void doRegisterBean(Class<T> beanClass, String name,
Class<? extends Annotation>[] qualifiers, Supplier<T> supplier,
BeanDefinitionCustomizer[] customizers) {
// 構造方法中會解析AnnotationMetadata元數據
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));
// 解析Lazy,Primary,DependsOn,Role等屬性
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);
// 處理Scope的proxyMode
definitionHolder = AnnotationConfigUtils
.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 註冊到容器
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
// BeanDefinitionReaderUtils.registerBeanDefinition(...)
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 將Bean註冊到BeanDefinitionRegistry
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);
}
}
}
此處的registry是AnnotationConfigApplicationContext對象,registerBeanDefinition方法的實現在GenericApplicationContext類:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
// beanFactory.registerBeanDefinition(...)
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
this.beanDefinitionMap.put(beanName, beanDefinition);
} 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;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
} else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
@Bean註解
@Bean註解註入的Bean最終在ConfigurationClassBeanDefinitionReader的loadBeanDefinitionsForBeanMethod方法註冊BeanDefinition:
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
return;
}
// 創建ConfigurationClassBeanDefinition
// 是RootBeanDefinition的子類
ConfigurationClassBeanDefinition beanDef =
new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(
((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
} else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
} else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
@ComponentScan註解
支持@ComponentScan註解的最終邏輯在ClassPathScanningCandidateComponentProvider類的scanCandidateComponents方法中:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
// 此處獲取到的是SimpleMetadataReader對象,
// 內部使用ASM解析.class文件封裝AnnotationMetadata對象
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 判斷是一個Component
if (isCandidateComponent(metadataReader)) {
// 創建ScannedGenericBeanDefinition對象
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}