BeanDefinition 继承图

对于 BeanDefinition 有一个抽象类的实现是 AbstractBeanDefinition,而 AbstractBeanDefinition 有很多子类的实现,如:GenericBeanDefinition,ChildBeanDefinition,RootBeanDefinition 等
AbstractBeanDefinition 是一个抽象的 BD,所以不能被实例化,所以我们要用 BD 来描述一个 Bean,就需要用到 AbstractBeanDefinition 的实现类
那么问题来 ,如果我们希望手工注册一个 BeanDefinition 的话,我们选择哪一个呢?
选择什么样的 BeanDefinition ?
其实通过名字就可以看出来,我们可以选择 GenericBeanDefinition(通用的 BD),为什么呢?
ChildBeanDefinition
我们先看 Spring 对 ChildBeanDefinition 的说明
* NOTE: Since Spring 2.5, the preferred way to register bean* definitions programmatically is the {@link GenericBeanDefinition} class,* which allows to dynamically define parent dependencies through the* {@link GenericBeanDefinition#setParentName} method. This effectively* supersedes the ChildBeanDefinition class for most use cases.
必须设置 parent bean 定义,spring 并没有提供无参构造方法,必须通过构造函数指定,只能作为子 BD 一般使用 ChildBeanDefinition 是确定了父子关系的 BeanDefinition
在 spring2.5 之前据说是配合 RootBeanDefinition 一起使用 但是现在的版本可以配合 {@link GenericBeanDefinition#setParentName} 使用了 未来很可能会被标记过时或者淘汰
这个类的实例化一般是通过构造方法设置的,并且一定要传 父BD 的名字 这是 ChildBeanDefinition 最大的局限了。 所以 ChildBeanDefinition 并不能当作一个普通的 DB 存在
所以这个 Child BD,我们现在已经不在使用了
RootBeanDefinition
RootBeanDefinition 可以配合 ChildBeanDefinition 一起使用,这样相同的代码我们就可以不需要重复编写,这就是 RootBeanDefinition 的作用
RootBeanDefinition 通常作为 parent BD 出现的,也可以作为普通 BD,唯一**不能作为 子 BD 出现,因为作为子类出现的话,setParentName 会抛出异常**
@Overridepublic void setParentName(@Nullable String parentName) {if (parentName != null) {throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");}}
当作 BD 的模板进行使用
当 RBD 作为 BD 模板使用的时候,就不要设置 BeanClass 属性了,需要使用 rbd.setAbstract(true); 来标识其为一个 Abstract Class,以供其他类使用
RootBeanDefinition rbd = new RootBeanDefinition();rbd.setScope(BeanDefinition.SCOPE_SINGLETON);rbd.setLazyInit(false);rbd.setAbstract(true);
当作为一个真实的 BD
RBD 也可以当作一个真实的 BD 来使用,需要设置 rbd.setBeanClass(xxx.class) ,就不需要设置 Abstract 属性了
public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.register(AppConfig.class);RootBeanDefinition rbd = new RootBeanDefinition();rbd.setScope(BeanDefinition.SCOPE_SINGLETON);rbd.setLazyInit(false);rbd.setBeanClass(UserService.class);ac.registerBeanDefinition("userService", rbd);// 相当于继承了 RootBeanDefinitionChildBeanDefinition cbd = new ChildBeanDefinition("userService");cbd.setBeanClass(IndexService.class);ac.registerBeanDefinition("indexService", cbd);ac.refresh();System.out.println(ac.getBean("userService"));System.out.println(ac.getBean("indexService"));}}
GenericBeanDefinition
GenericBeanDefinition 是 Spring 2.5 之后推出的,既可以做普通 BD,也可以做子 BD,甚至可以做父 BD,可以完全替代 ChildBeanDefinition(通过 setParentName),但是不能完全取代 RootBeanDefinition
既然 GBD 可以做父 BD,那么为什么不能完全取代 RootBeanDefinition 呢? 这和 bean 的合并有关系,后面的章节会详细解释
public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.register(AppConfig.class);GenericBeanDefinition rbd = new GenericBeanDefinition();rbd.setLazyInit(false);rbd.setScope(GenericBeanDefinition.SCOPE_SINGLETON);rbd.setBeanClass(UserService.class);ac.registerBeanDefinition("userService", rbd);GenericBeanDefinition cbd = new GenericBeanDefinition();cbd.setParentName("userService");cbd.setBeanClass(IndexService.class);ac.registerBeanDefinition("indexService", cbd);ac.refresh();System.out.println(ac.getBean("userService"));System.out.println(ac.getBean("indexService"));}}
ConfigurationClassBeanDefinition
这个 BD 又是做什么的呢?我们知道在 Spring 中,我们经常会使用 @Bean 的注解来注入一些第三方类,此时这些类就会用 ConfigurationClassBeanDefinition 来定义
ScannedGenericBeanDefinition
见名知意,一定和扫描有关,对咯,这个 BD,就是 Spring 在进行扫描的时候,发现有 @Component 或者 @Service 等注解标注的 bean 的时候,就会用 ScannedGenericBeanDefinition 来定义
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {// ... 省略代码无数if (isCandidateComponent(metadataReader)) {// ★ 创建了 ScannedGenericBeanDefinition// ★ 这里就证明了通过注解扫描出来的类都是 ScannedGenericBeanDefinitionScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);// 关键代码:返回是(否是一个独立的类(可以通过构造函数创建)并且 不能是接口和抽象类) 或者(是一个抽象类,并且 有 Lookup 注解)if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}// 省略代码无数}
AnnotatedGenericBeanDefinition
这个 DB 描述的,通常都是 Spring 初始化时,通过 register 来注册的 bean,如:加了 @Configuration 的注解类,就是用 AnnotatedGenericBeanDefinition 来定义的
@Overridepublic void register(Class<?>... componentClasses) {Assert.notEmpty(componentClasses, "At least one component class must be specified");this.reader.register(componentClasses);}
这里的 reader 其实就是 private final AnnotatedBeanDefinitionReader reader;

