一.前言
这一篇来看看 SpringIOC 里面的一个细节点 , 来简单看看 BeanDefinition 这个对象 , 以及有没有办法对其进行定制.
CASE 备份 : 👉 gitee.com/antblack/ca…
二. BeanDefinition 的体系
2.1 体系概览
这里面需要关注的几个类分别为 :
- BeanDefinition 接口 : 顶层接口 , 抽象了Bean加载的方法
- AbstractBeanDefinition : 提供了多数方法的默认实现
- RootBeanDefinition : Spring BeanFactory 运行时统一的 BeanDefinition 视图
- GenericBeanDefinition : 编程方式注册 BeanDefinition 的首选类
- ChildBeanDefinition : 可继承BeanDefinition
下面来解释一下这里面说的一些概念 :
什么叫统一视图 ?
稍微从跟踪一下源码就能发现 , 从 xml 或者 JavaConfig 以及 Spring 默认加载的Bean配置类 ,最终都会被修饰为 RootBeanDefinition
GenericBeanDefinition 怎么用 ?
GenericBeanDefinition 是通过编程方式注入的 BeanDefinition 所对应的类 ,通常都是该类的子类 , 包括非Spring 的 ConfigBean 和 ServiceBean
ChildBeanDefinition 又做了什么 ?
一种可以继承 parent 配置的 BeanDefinition , 在加载环节中会通过 AbstractBeanFactory#getMergedLocalBeanDefinition() 来将 child 和 parent bean definition 进行合并。
- BeanDefinition 进行 merge 操作时,会将 child 的属性与 parent 的属性进行合并,当有相同属性时,以 child 的为准
- 如果是 Map 形式的配置 , 会取并集
2.2 BeanDefinition 的作用
- 存储属性 : 基于接口 AttributeAccessor 实现
- 存储元数据配置 : 基于 BeanMetadataElement 实现
- 描述类的信息 : 包括Bean名称 , Primary 属性 , priority 配置 等等
- Bean 的加载 : 例如 getBeansOfType , getBean 等等
总结其实就是一句话 : BeanDefinition 主要承载了Bean的元数据信息 ,同时描述了Bean在Spring体系中的加载方式 , 容器通过 BeanDefinition 中的配置来加载一个Bean
三. BeanDefinition 的载入
3.1 载入的入口
S1 : 启动配置类的载入
Spring 中第一个载入的 BeanDefinition 即为 RootBeanDefinition , 主要通过 AnnotationConfigUtils # registerAnnotationConfigProcessors 方法进行加载
在这个环节中会通过加载的方式分别载入多个不同的 RootBeanDefinition , 这里是 Contain 关系 :
// internalConfigurationAnnotationProcessor if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { // 构建对应的 PostProcessor 并且载入 RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); } // internalAutowiredAnnotationProcessor if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { //..... }
在这个环节中 , 基本上都是在通过 registerPostProcessor 来注册各类加载类 , 我把这些看成根类 .
这些类通常为 Spring 进行服务 , 用来配置各类信息和加载封装 Bean
S2 : 普通配置类的载入
普通类的载入包括 SpringApplication
和一些自定义的个人配置类 , 这些类主要为了对非 Spring 的组件进行注册 , 配置 , 注入等操作
这一类通常通过 registerBean 来实现Bean的注册 , 注册的入口也很多 :
包括 AnnotatedBeanDefinitionReader
和 ConfigurationClassPostProcessor
等, 不难发现这一类 BeanDefinition 通常都是由 RootBeanDefinition 装载的类进行载入的
通常注册出来的对象也为 AnnotatedGenericBeanDefinition 和 GenericBeanDefinition 的子类等
3.2 保存的逻辑
BeanDefinition 会在 DefaultListableBeanFactory # registerBeanDefinition
中进行注册.
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // S1 : 会对 BeanDefinition 进行校验 , 主要是MethodOverrides和FactoryMethodName不能同时存在 // -- 工厂方法必须创建具体的 Bean 实例 , 而 methodOverrides 会创建代理类且进行增强 // -- 也就是说 工厂需要实例 , 不能是代理类 if (beanDefinition instanceof AbstractBeanDefinition) { ((AbstractBeanDefinition) beanDefinition).validate(); } // S2 : 判断 BeanDefinition 是否已经存在 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { // 是否允许同名Bean重写 , 因为此处已经存在一个了 , 不能重写则直接异常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); }else if (existingDefinition.getRole()
3.3 使用的方式
BeanDefinition 的批量处理流程也是在 DefaultListableBeanFactory
中进行的
public void preInstantiateSingletons() throws BeansException { List beanNames = new ArrayList(this.beanDefinitionNames); // 对所有的 BeanDefinition 进行循环处理 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 排除掉懒加载的Bean if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 此处省略工厂类的判断及处理 ... // 进入Bean获取逻辑 getBean(beanName); } } //..... }
总结
分析 BeanDefinition 不是这阶段的主要目的 , 后续会有几篇应用的文章来着重思考下如何进行业务定制
其实写源码文章是最轻松的 , 看懂就完事了 , 而写定制或者业务 , 往往写着写着发现有地方没搞懂 , 就需要回头继续看这个点 , 难度要大得多…….
附录 : BeanDefinition 功能一览
以上就是SpringIOC BeanDefinition的加载流程详解的详细内容,更多关于SpringIOC BeanDefinition加载的资料请关注IT俱乐部其它相关文章!