spring启动流程 (3) BeanDefinition详解-全球焦点
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());}@Overridepublic final AnnotationMetadata getMetadata() {return this.metadata;}@Overridepublic 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;}@Overridepublic final AnnotationMetadata getMetadata() {return this.metadata;}@Overridepublic 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 void doRegisterBean(Class beanClass, String name,Class extends Annotation>[] qualifiers, Supplier 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的proxyModedefinitionHolder = 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注册到BeanDefinitionRegistryregistry.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 updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;removeManualSingletonName(beanName);}} else {// Still in startup registration phasethis.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 aliasesList names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));String beanName = (!names.isEmpty() ? names.remove(0) : methodName);// Register aliases even when overriddenfor (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 methodif (configClass.getMetadata() instanceof StandardAnnotationMetadata) {beanDef.setBeanClass( ((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());} else {beanDef.setBeanClassName(configClass.getMetadata().getClassName());}beanDef.setUniqueFactoryMethodName(methodName);} else {// instance @Bean methodbeanDef.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 scopingScopedProxyMode 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 necessaryBeanDefinition 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 scanCandidateComponents(String basePackage) {Set 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);// 判断是一个Componentif (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;}