BeanDefinition在Spring初始化阶段保存Bean的元数据信息,包括Class名称、Scope、构造方法参数、属性值等信息,本文将介绍一下BeanDefinition接口、重要的实现类,以及在Spring中的使用示例。
用于描述了一个Bean实例,该Bean实例具有属性、构造方法参数以及由具体实现提供的其他信息。
(资料图)
这是一个基础接口:主要目的是允许BeanFactoryPostProcessor获取和修改Bean实例属性和其他元数据。
封装以下信息:
实现了BeanDefinition接口,具体的、完整的BeanDefinition基类,抽取出GenericBeanDefinition、RootBeanDefinition和ChildBeanDefinition的公共属性。
扩展的属性:
继承AbstractBeanDefinition类。
RootBeanDefinition表示在运行时支持BeanFactory中指定Bean的合并BeanDefinition。它可能是由多个相互继承的原始BeanDefinition创建的,通常注册为GenericBeanDefinitions。RootBeanDefinition本质上是运行时的"统一"RootBeanDefinition视图。
RootBeanDefinition也可以用于在配置阶段注册各个BeanDefinition。然而,自Spring2.5以来,以编程方式注册BeanDefinition的首选方式是GenericBeanDefinition类。GenericBeanDefinition的优势是允许动态定义父依赖项,而不是将角色硬编码为RootBeanDefinition。
扩展的属性:
继承AbstractBeanDefinition类。
GenericBeanDefinition是用于构建标准BeanDefinition的一站式组件。与其他BeanDefinition一样,它允许指定一个类以及可选的构造方法参数和属性。另外,从父BeanDefinition派生可以通过parentName属性灵活配置。
通常,使用GenericBeanDefinition类来注册用户可见的BeanDefinition,后置处理器可能会对其进行操作,甚至可能重新配置parentName属性。如果父子关系恰好是预先确定的,请使用RootBeanDefinition和ChildBeanDefinition。
继承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();}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;}}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;}}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最终在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注解的最终逻辑在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;} 关键词:
“非物质文化遗产进校园活动”展演活动在凤翔学校顺利开展
信阳市市文广旅局举办非物质文化遗产申报放权赋能培训会召开
淮南市第五批市级非物质文化遗产代表性项目公布
”陕西省非物质文化遗产研究基地“在榆林成立
定了!在郑州举办的2022中国非遗年会延期举办
喜讯!甘肃省古籍保护中心“古籍修复技艺”被列为省级非遗
从“非遗进校园”到“非遗在校园”!广东发布20个优秀案例