顾名思义,BeanDefinition是指Bean的定义信息。这个类的设计相当重要,对理解SpringBoot的扩展点、生命周期等有很大帮助。
BeanDefinition的javadoc并没有提供有价值的信息,但可以从BeanDefinition接口定义的方法入手,来看BeanDefinition包含了哪些定义信息。
1.Bean的类信息
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
2.Bean的属性
void setScope(@Nullable String scope);
String getScope();
void setPrimary(boolean primary);
boolean isPrimary();
void setDescription(@Nullable String description);
String getDescription();
3.Bean的行为特性
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setInitMethodName(@Nullable String initMethodName);
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
String getDestroyMethodName();
4.Bean与其他Bean的关系
void setParentName(@Nullable String parentName);
String getParentName();
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
5.Bean的配置属性
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
以上并没有把全部方法列出来,但足以看出BeanDefinition几乎已经把Bean的所有信息都收集并封装起来了。
借助IDEA,生成BeanDefinition接口的上下级继承和派生关系:
可以发现,BeanDefinition并不是顶层接口,它的上层有一些父接口,下层也有一些扩展实现。
AttributeAccessor是BeanDefinition的父接口,由类名可知它是一个属性访问器,用于获取属性值、写入属性值、移除属性、判断是否存在某个属性。
public interface AttributeAccessor {
// 设置bean对象中属性的值
void setAttribute(String name, @Nullable Object value);
// 获取bean对象中指定属性的值
Object getAttribute(String name);
// 移除bean对象中指定属性
Object removeAttribute(String name);
// 判断bean对象中是否存在指定的属性
boolean hasAttribute(String name);
// 获取bean对象中所有的属性
String[] attributeNames();
}
BeanDefinition接口继承自AttributeAccessor,因此具有配置Bean属性(访问、修改、移除等)的功能。
BeanMetadataElement是BeanDefinition的另一个父接口,类名直译为存放Bean的元数据的元素。这个接口只有一个方法:
public interface BeanMetadataElement {
@Nullable
default Object getSource() {
return null;
}
}
这个方法用于获取Bean的资源来源,也即Bean的文件路径。一般情况下,项目中所编写的所有注册到IOC容器的Bean,都是从本地磁盘上的.class文件加载进来的,所以此处获取的就是这个.class文件(Resource对象或者File对象)。
AbstractBeanDefinition是BeanDefinition接口的基本抽象实现,定义了部分属性和逻辑实现。AbstractBeanDefinition重写BeanDefinition中定义的方法并操作这些属性。
// Bean的全限定类名
private volatile Object beanClass;
// 默认作用域,""与singleton等价,也就是默认单实例
public static final String SCOPE_DEFAULT = "";
private String scope = SCOPE_DEFAULT;
// 默认Bean都不是抽象的
private boolean abstractFlag = false;
// 是否延迟初始化
private Boolean lazyInit;
// 默认不是首选Bean
private boolean primary = false;
// Bean的构造方法参数和参数值列表
private ConstructorArgumentValues constructorArgumentValues;
// Bean的属性和属性值集合
private MutablePropertyValues propertyValues;
// Bean的初始化方法和销毁方法
private String initMethodName;
private String destroyMethodName;
// Bean的资料来源
private Resource resource;
// ...
Base class for concrete, full-fledged
BeanDefinition
classes, factoring out common properties ofGenericBeanDefinition
,RootBeanDefinition
, andChildBeanDefinition
.
AbstractBeanDefinition是具体的、完整的BeanDefinition的基类,分解出GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition的公共属性。
从javadoc得知,AbstractBeanDefinition中定义的属性是一些公共属性,意味着不同的BeanDefinition落地实现,内部的属性还是有差异的。
GenericBeanDefinition是BeanDefinition的其中一个落地实现类。Generic表示“通用的”“一般的”,因此GenericBeanDefinition具有一般性。
GenericBeanDefinition的源码非常简单,在继承AbstractBeanDefinition类之后,只定义了一个属性:parentName。
public class GenericBeanDefinition extends AbstractBeanDefinition {
private String parentName;
// ...
}
GenericBeanDefinition is a one-stop shop for standard bean definition purposes. Like any bean definition, it allows for specifying a class plus optionally constructor argument values and property values. Additionally, deriving from a parent bean definition can be flexibly configured through the “parentName” property.
第一段:GenericBeanDefinition是实现标准Bean定义的一站式服务。和任何Bean定义一样,它允许指定的类和可选的构造函数参数值和属性值。此外,可以通过parentName属性灵活地配置父级Bean定义。
In general, use this
GenericBeanDefinition
class for the purpose of registering user-visible bean definitions (which a post-processor might operate on, potentially even reconfiguring the parent name). UseRootBeanDefinition
/ChildBeanDefinition
where parent/child relationships happen to be pre-determined.
第二段:通常,使用GenericBeanDefinition类的目的是注册用户可见的Bean定义(后处理器可能会对其操作,甚至可能重新配置父级名称)。在父子关系预先确定的地方使用RootBeanDefinition和ChildBeanDefinition。
由此可见,GenericBeanDefinition是通用的BeanDefinition落地实现,并且具有层次性。
ChildBeanDefinition从类名来看,是指子定义信息。因此在继承AbstractBeanDefinition的同时,也带有parentName属性,和GenericBeanDefinition几乎是一模一样的。
在javadoc中描述了ChildBeanDefinition和GenericBeanDefinition的区别:
NOTE: Since Spring 2.5, the preferred way to register bean definitions programmatically is the
GenericBeanDefinition
class, which allows to dynamically define parent dependencies through thesetParentName
method. This effectively supersedes the ChildBeanDefinition class for most use cases.
自SpringFramework 2.5以来,以编程方式注册Bean定义的首选方法是GenericBeanDefinition类,它允许通过setParentName
方法动态定义父依赖项。在大多数用例中,这有效地替代了ChildBeanDefinition类。
可见,官方是推荐使用GenericBeanDefinition的。
在源码上,两者也有一些不一样:GenericBeanDefinition有不带参数的构造方法,而ChildBeanDefinition全部构造方法都带parentName参数,这样做是因为ChildBeanDefinition是在父子关系预先确定的地方使用的。
RootBeanDefinition的类名中有“根”的概念,这就意味着RootBeanDefinition只能作为单独的BeanDefinition或者父级BeanDefinition出现。
从源码得知,RootBeanDefinition在AbstractBeanDefinition的基础上,扩展了一些Bean的其他信息:
// BeanDefinition的引用持有,存放了Bean的别名
private BeanDefinitionHolder decoratedDefinition;
// Bean上面的注解信息
private AnnotatedElement qualifiedElement;
// Bean中的泛型
volatile ResolvableType targetType;
// BeanDefinition对应的真实Bean
volatile Class<?> resolvedTargetType;
// 是否是FactoryBean
volatile Boolean isFactoryBean;
//工厂Bean方法返回的类型
volatile ResolvableType factoryMethodReturnType;
// ...
扩展的信息包括:id和别名、注解信息、工厂相关信息(是否为工厂Bean等等)。可见,RootBeanDefinition在底层做了更多的事情。(至于做了什么事情,暂时没有深入研究,后续做补充)
至此,可以对BeanDefinition的结构与设计做个小结:
通过两个简单的例子,直观感受BeanDefinition的设计,以及其中封装的属性。
使用模式注解+组件扫描的方式,每扫描到一个类,就相当于构建了一个BeanDefinition。
(1)定义一个Person类,并标注@Component:
@Component
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(2)使用AnnotationConfigApplicationContext扫描指定包路径下标注了@Component直接的组件:
public class DemoApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.star.springboot.test03");
BeanDefinition beanDefinition = context.getBeanDefinition("person");
System.out.println(beanDefinition);
}
}
(3)打印BeanDefinition信息:
Generic bean: class [com.star.springboot.test03.Person];
scope=singleton; abstract=false; lazyInit=null; autowireMode=0;
dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in file [D:\learnspace\workspace\java_src\springboot-demo\springboot-03-ioc\target\classes\com\star\springboot\test03\Person.class]
由结果可知,这是一个GenericBeanDefinition,且定义来源在类的.class文件中。
(1)编写注册了Person的注解配置类
@Configuration
public class PersonConfiguration {
@Bean
public Person person2222() {
return new Person();
}
}
(2)使用AnnotationConfigApplicationContext注册该注解配置类(和上例进行比较):
public class DemoApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.star.springboot.test03");
BeanDefinition beanDefinition = context.getBeanDefinition("person");
System.out.println(beanDefinition);
System.out.println("=======================");
AnnotationConfigApplicationContext context2 = new AnnotationConfigApplicationContext(PersonConfiguration.class);
BeanDefinition beanDefinition2 = context2.getBeanDefinition("person2222");
System.out.println(beanDefinition2);
}
}
(3)打印BeanDefinition信息:
Generic bean: class [com.star.springboot.test03.Person];
scope=singleton; abstract=false; lazyInit=null; autowireMode=0;
dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in file [D:\learnspace\workspace\java_src\springboot-demo\springboot-03-ioc\target\classes\com\star\springboot\test03\Person.class]
=======================
Root bean: class [null];
scope=; abstract=false; lazyInit=null; autowireMode=3;
dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=personConfiguration;
factoryMethodName=person2222; initMethodName=null; destroyMethodName=(inferred);
defined in com.star.springboot.test03.PersonConfiguration
由结果可知,两种方式获取的BeanDefinition区别很大:
基于组件扫描 | 基于@Bean | |
---|---|---|
BeanDefinition类型 | Generic bean | Root bean |
className | [com.star.springboot.test03.Person] | [null] |
scope | singleton | |
autowireMode | 0 | 3 |
factoryBeanName | null | personConfiguration |
factoryMethodName | null | person2222 |
destroyMethodName | null | (inferred) |
defined in | file[Person.class] | PersonConfiguration |
为什么两种不同的Bean定义方式在实际运行时会有如此大的差别呢?通过查看源码可以大致梳理出其逻辑:
ClassPathBeanDefinitionScanner.java
public int scan(String... basePackages) {
// ...
// 调用核心扫描方法是doScan
doScan(basePackages);
// ...
}
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// ...
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 调用父类findCandidateComponents方法
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// ...
}
}
return beanDefinitions;
}
ClassPathScanningCandidateComponentProvider.java
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {
return scanCandidateComponents(basePackage);
}
}
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
// ...
// 创建ScannedGenericBeanDefinition并返回
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
// ...
candidates.add(sbd);
// ...
return candidates;
}
AnnotationConfigApplicationContext.java
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
// 入口
refresh();
}
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
// ...
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// ...
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// ...
}
PostProcessorRegistrationDelegate.java
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// ...
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
// ...
}
ConfigurationClassPostProcessor.java
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// ...
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// ...
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// ...
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
//...
}
ConfigurationClassBeanDefinitionReader.java
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// ...
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 为@Bean方法加载BeanDefinition
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// ...
}
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// ...
// 创建ConfigurationClassBeanDefinition对象并返回
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
// ...
}
BeanDefinition解析完成后,最终要转化为bean对象,这中间就有BeanDefinition注册、解析生成bean对象的过程,而管理BeanDefinition的核心就是BeanDefinitionRegistry。
Interface for registries that hold bean definitions, for example RootBeanDefinition and ChildBeanDefinition instances. Typically implemented by BeanFactories that internally work with the AbstractBeanDefinition hierarchy.
第一段:BeanDefinitionRegistry是保存Bean定义的注册中心,例如保存RootBeanDefinition和ChildBeanDefinition实例。通常由BeanFactories实现,它在内部使用AbstractBeanDefinition层次结构。
This is the only interface in Spring’s bean factory packages that encapsulates registration of bean definitions. The standard BeanFactory interfaces only cover access to a fully configured factory instance.
第二段:这是SpringFramework的 Bean工厂包中封装Bean定义注册的唯一接口。标准的BeanFactory接口只涵盖对完全配置的工厂实例的访问。
Spring’s bean definition readers expect to work on an implementation of this interface. Known implementors within the Spring core are DefaultListableBeanFactory and GenericApplicationContext.
第三段:SpringFramework的Bean定义读取器在这个接口的实现上工作。SpringFramework核心中已知的实现类有DefaultListableBeanFactory和GenericApplicationContext。
从javadoc可知,BeanDefinitionRegistry是维护BeanDefinition的注册中心,它内部存放了IOC容器中Bean的定义信息,同时也是支撑其他组件和动态注册Bean的重要组件。
从源码来看,BeanDefinitionRegistry本质是一个存放BeanDefinition的容器:
// 源自实现类DefaultListableBeanFactory
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
这里需要注意,DefaultListableBeanFactory不仅是BeanDefinitionRegistry的主要实现,也是BeanFactory的主要实现,因此DefaultListableBeanFactory不仅是bean对象的统一管理容器,而且是BeanDefinition的统一管理容器。
其次,BeanDefinitionRegistry包含BeanDefinition的注册功能,即增、删、查:
// 注册
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
// 移除
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 获取
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
最后,在 SpringBoot源码解读与原理分析(二)组件装配 中使用ImportBeanDefinitionRegistrar以编程式向IOC容器中注册bean对象时,其核心方法registerBeanDefinitions的入参就有一个BeanDefinitionRegistry,自定义的组件的定义信息将注册到BeanDefinitionRegistry中。
public class WaiterRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("waiter222", new RootBeanDefinition(Waiter.class));
}
}
为了统一管理bean对象。
在面向对象的java开发中,是先编写Class类,再new出对象。Class类就相当于定义信息,有即定的规则(如有构造方法、getter、setter等)。按照这些规则,就可以生成对象、设定属性等等。
设计BeanDefinition的意义就是对IOC容器中的Bean进行定义抽取,只有抽取成统一类型或格式的模型,才能在后续的bean对象管理时进行统一管理,或者对特定的Bean进行特殊化处理。
简单地说,就是有了定义信息,按照既定的规则,就可以任意解析和生成bean对象,也可以根据实际需求对解析和生成对象的过程进行任意扩展。
分类专栏:SpringBoot源码解读与原理分析