本文是自己学习的一个总结
BeanDefinition是Spring Framework中定义Bean的配置原信息接口,其中包含
BeanFactory获取对象的方式是这样的
//container是已经定义的一个容器,BeanFactory类型
ClassA a = container.getBean("a");
虽然BeanFactory会自动维护对象,但我们得先让容器知道哪些对象需要维护,这里就涉及到BeanFactory的对象注册和依赖绑定方式。
Spring对象注册和依赖绑定主要有直接编码方式、外部文件配置方式(这里不记录具体的绑定方式,只是记录依赖绑定的类BeanDefinitionRegistry和其他相关类)。
前面我们知道,BeanFactory内提供了获取容器中管理Bean对象的方法和一些获取Bean对象的属性的方法,但Bean被容器管理之前要先被注册,有依赖的建立依赖,而这些服务的提供者不是BeanFactory而是BeanDefinition。BeanDefinition和BeanFactory的关系图如下。
如果我们直接使用编码方式来绑定依赖的话,会使用同时继承BeanFactory和BeanDefinitionRegistry的DefaultListableBeanFactory来完成注册,然后将注册号的DefaultListableBeanFactory当做BeanFactory类型返回(这样的好处就是外界就只能调用作为BeanFactory类型的返回对象中,关于获取Bean的服务)。
下面的代码展示了这一过程,这段代码演示了使用DefaultListableBeanFactory注册几个Bean(注册Provider,Listener和Persister,其中Provider关联Listener和Persister,即Provider的构造函数的参数类型是Listener和Persiter),然后再从DefaultListableBeanFactory容器中取出其中一个Bean对象。
public static void main(String[] args) {
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory container = (BeanFactory) bindViaCode(beanRegistry);
Provider a = container.getBean("new provider");
}
BeanFactory bindViaCode(DefaultListableBeanFactory registry) {
//将三个类放到BeanDefinition的实现类AbstractBeanDefinition中,等会再将他们注册到registry中
AbstractBeanDefinition newProvider = new RootBeanDefinition(Provider.class, true);
AbstractBeanDefinition newListener = new RootBeanDefinition(Listener.class, true);
AbstractBeanDefinition newPersister = new RootBeanDefinition(Persister.class, true);
//将三个类注册到容器中,还没完,因为Provider的构造函数需要另外两个类对象
registry.registerBeanDefinition("new provider", newProvider);
registry.registerBeanDefinition("new listener", newListener);
registry.registerBeanDefinition("new persister", newPersister);
//构造函数的注入依赖方式
ConstructiorArgumentValues argValues = new ConstructorArgument.Values();
argValues.addIndexedArgumentValue(0, newListener);
argValues.addIndexedArgumentValue(0, newListener);
newProvider.setConstructorArgumentValues(argValues);
//已BeanFactory的类型返回,这样客户端就只能调用获取Bean的方法,不能再新注册Bean到容器中,有利于封装。
return (BeanFactory) registry;
}
当然,现在写工程项目很少会用到代码手动注册的方式,注解@Autowired会用的比较多,这里只是为了展示DefaultListableBeanFactory、BeanDefinition、BeanFactory的关系才贴上这些代码。
属性 | 说明 |
---|---|
beanClass | Bean的全类名,必须是具体类,不能是抽象类或接口。因为Bean是实例对象,抽象类或接口是不能实例的,不能作为Bean的类名。 |
name | Bean的名称或者id |
scope | Bean的作用域,比如默认的单例模式,还有原生模式。 |
constructorArgumentValues | Bean的构造器参数,用于依赖注入。 |
propertiesValues | Bean中成员属性 |
autowireMode | 自动绑定的模式,比如byName,通过名称自动绑定;byType,通过类型自动绑定等。这是可以设置的。 |
lazyInit | boolean值,是否延迟初始化。默认是非延迟初始化。延迟化的好处是可以有效地减少启动时间。 |
initMethodName | Bean初始化回调方法名称 |
destroyMethodName | Bean销毁回调方法名称 |
BeanDefinition的构建主要有两种方法。
BeanDefinitionBuilder内部有许多静态方法构建BeanDefinition。这些静态方法分为以下三种,所有的静态方法这三个方法的重载形式。
三者从名字上其实就可以看出区别。虽然三个方法返回的都是BeanDefinitionBuilder,但是三者其实是和三个BeanDefinition相关。rootBeanDefinition相关的是RootBeanDefinition。RootBeanDefinition和ChildBeanDefinition是相互配合的,ChildBeanDefinition可以直接继承RootBeanDefinition中的元信息。比如下面的代码。
//假设容器中已定义一个RootBeanDefinition命名为rootBeanDefinition。
//下面这段语句就令childBeanDefinition直接快速继承rootBeanDefinition中的元信息。
//GenericBeanDefinition就没办法这样快速继承。
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition("rootBeanDefinition");
GenericBeanDefinition就相关一个普通的GenericBeanDefinition。三者其实都是一样的,只是GenericBeanDefinition没法像ChildBeanDefinition和RootBeanDefinition一样相互联动。
下面我们使用简单示例,使用genericBeanDefintion构建简单的BeanDefinition。
我们想构建一个描述User类的BeanDefinition。User类的描述如下。
public class User {
private Long id;
private String name;
//省略setter和getter
}
下面开始通过BeanDefinitionBuilder构建BeanDefinition
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
//设置Bean的属性
beanDefinitionBuilder.addPropertyValue("name", "用户1");
beanDefinitionBuilder.addPropertyValue("id", 10);
//获取到BeanDefintion
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
这种方式相较于上一种就比较直接,我们不借用BeanDefinitonBuilder这个中间工具来构建BeanDefinition,而是直接创建一个BeanDefinition,然后直接设置元信息。
AbstractBeanDefintion的子类中最常见和通用的就是GenericBeanDefintion,下面举例也是使用GenericBeanDefintion。
//直接new一个GenericBeanDefinition
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
//然后设置要描述的类
genericBeanDefinition.setBeanClass(User.class);
//设置类的Property,不能像BeanDefinitionBuilder一样直接设置,要通过MutablePropertyValues这个中间人
MutablePropertyValues();
propertyValues.addPropertyValue("name", "用户1");
propertyValues.addPropertyValue("id", 10); //也可以写成propertyValues.add("id", 1).add("name", "用户1");
genericBeanDefinition.setPropertyValues(propertyValues);
回到这张图,将BeanDefinition定义好之后,还要将其注册到容器中
将BeanDefinition注册到容器中有两种种方式