Bean 在被创建之前是什么?@Bean 方法、@Component、手写注册的定义有什么不同?创建之前能不能改?父子定义怎么合并?同名的 Bean 为什么在 Boot 里会报错?这篇直接读 BeanDefinition 的各个属性,在 Spring Framework 7.0.9 上逐项验证。
manual 定义类型=GenericBeanDefinition 类=Main$Greeter scope=(空=singleton) lazy=true factoryMethod=null 来源=null main.Scanned 定义类型=ScannedGenericBeanDefinition 类=Main$Scanned scope=singleton lazy=false factoryMethod=null 来源=Main$Scanned.class main.Conf 定义类型=ScannedGenericBeanDefinition 类=Main$Conf$$SpringCGLIB$$0 scope=singleton lazy=false factoryMethod=null 来源=Main$Conf.class viaBean 定义类型=ConfigurationClassBeanDefinition 类=null scope=(空=singleton) lazy=false factoryMethod=viaBean 来源=demo.Main$Conf 创建之前 manual 的单例已创建吗?false(lazy=true);getBean 之后 Greeter(手写的定义)#48e 已创建=true viaBean 的实例:Greeter(来自 @Bean)#158;@Bean 的 initMethod 属性在定义里:init
手写、扫描、@Bean 方法各有不同的 BeanDefinition 类型;@Bean 的定义没有 beanClassName,只有 factoryMethod。
BFPP 看到的定义:scope=singleton greeting=原值 refresh 之后两次 getBean:Greeter(被 BFPP 改过)#489 与 Greeter(被 BFPP 改过)#385;同一个对象?false(定义里的 scope 被改成了 prototype)
BeanFactoryPostProcessor 在 Bean 创建前拿到定义,可以改属性值甚至 scope。
child 自己的定义:beanClassName=null initMethod=null 属性数=0 child 合并后:类=Main$Greeter initMethod=init greeting=父定义的值;合并后的类型 RootBeanDefinition getBean(child)=Greeter(父定义的值)#b3c getBean(child2)=Greeter(子定义覆盖)#45c getBean(abstract 的 parentDef):BeanIsAbstractException 容器里 Greeter 类型的 Bean 个数:2(abstract 的定义不会被创建)
子定义继承父定义的类、init-method 和属性,合并成 RootBeanDefinition;abstract 的父定义不会被创建。
纯 Spring Framework 的 DefaultListableBeanFactory 默认 isAllowBeanDefinitionOverriding = true allowBeanDefinitionOverriding=true:没有报错,getBean(dup)=Greeter(第二个)#710 allowBeanDefinitionOverriding=false:BeanDefinitionOverrideException: Invalid bean definition with name 'dup' defined in null: Cannot register bean definition [Generic bean: class=demo.Main$Greeter; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null] for bean 'dup' since there is already [Generic bean: class=demo.Main$Greeter; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; fallback=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null] bound. SpringApplication 创建的上下文(AnnotationConfigApplicationContext)的 isAllowBeanDefinitionOverriding = false 纯 Spring Framework 里后注册的定义悄悄覆盖前面的;SpringApplication 创建的上下文把它设成 false(上面最后一行是实际读出来的值)
纯 Spring 默认允许后者覆盖前者,SpringApplication 的上下文不允许,启动时就报错。