写点什么

Spring 容器的核心组件

作者:IT巅峰技术
  • 2022 年 4 月 04 日
  • 本文字数:2501 字

    阅读完需:约 8 分钟

一、背景

不妨大胆推测一下:Spring 是如何处理我们的 Bean 的呢?


通过读取解析文件中的资源配置,将需要交给容器管理的类先找个地方集中起来(注册表),最后将这个注册表中所有的 Bean 定义实例化为 Bean。将 Bean 在内存中缓存起来(HashMap),在我们需要使用的时候根据 key 值直接取出来我们的对象。事实上,Spring 的确也是这么处理的。只不过它的设计远比我们所能想到的更要复杂与全面。


二、认识一下 BeanFactory

我们知道 Spring 使用 BeanFactory 来产生和管理 Bean。


    @Component   public class MyCompBean {      private String name="myCompBean";   }
@SpringBootApplication public class BootStarter {
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(BootStarter.class); //@Component Object myCompBean = context.getBean("myCompBean"); System.out.println(myCompBean); } }
复制代码


我们从 SpringApplication.run()方法入手,发现默认创建了 AnnotationConfigApplicationContext 作为 Spring 的上下文。如果依赖中有 spring-boot-starter-web 默认是创建 SERVLET 类型的 AnnotationConfigServletWebServerApplicationContext



public ConfigurableApplicationContext run(String... args) { // 省略部分代码... context = this.createApplicationContext(); // 省略部分代码...}
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch(this.webApplicationType) { case SERVLET: contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); break; case REACTIVE: contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"); break; default: contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext"); } } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } }
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }
复制代码


下面我们先看一下该类的 UML 图然后再逐步分析 Bean 的存储路径。



下面我们看一下 Bean(单例)获取的时序图(Spring 完全加载完成之后)


最终我们发现我们从容器中获取的 Bean 是从 DefaultSingletonRegistry 的 singletonObjects 中拿到的。我们看看这个是什么。没错!它就是一个 Map。(有没有觉得 Spring 不过如此?千万别这么想,你可知为了让咱使用起来尽量简单,它做了太多的工作。)


public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);}
复制代码

三、主角登场

DefaultListableBeanFactory 是整个 Bean 加载的核心部分,是 Spring 注册及加载 Bean 的默认实现。它继承了 AbstractAutowireCapableBeanFactory 并实现了 ConfigurableListableBeanFactory 以及 BeanDefinitionRegistry 接口 。



可以看出来,层次还是相当清晰的,我们先粗略的看看这些类都具备哪些功能。


  • AliasRegistrγ: 定义对 alias 的简单增删改等操作。

  • SimpleAliasRegistry: 主要使用 map 作为 alias 的缓存,并对接口 AliasRegistry 进行实现。

  • SingletonBeanRegistry:定义对单例的注册及获取 。

  • BeanFactory:定义获取 Bean 及 Bean 的各种属性 。

  • DefauItSingletonBeanRegistry:对接口 SingletonBeanRegistry 各函数的实现。

  • HierarchicalBeanFactory:继承 BeanFactory,也就是在 BeanFactory 定义的功能的基础上增加了对 parentFactory 的支持 。

  • BeanDefinitionRegistry: 定义对 BeanDefinition 的各种增删改操作 。

  • FactoryBeanRegistrySupport:在 DefaultSingletonBeanRegistry 基础上增加了对 FactoryBean 的特殊处理功能 。

  • ConfigurableBeanFactory:提供配直 Factory 的各种方法 。

  • ListableBeanFactory:根据各种条件获取 Bean 的配置清单 。

  • AbstractBeanFactory:综合 FactoryBeanRegistrySupport 和 ConfigurableBeanFactory 的 功能。

  • AutowireCapableBeanFactory:提供创建 Bean、自动注入、初始化以及应用 Bean 的后处理器 。

  • AbstractAutowireCapableBeanFactory:综合 AbstractBeanFactory 并对接口 AutowireCapableBeanFactory 进行实现。

  • ConfigurableListableBeanFactory: Beanfactory 配置清单,指定忽略类型及接口等。

  • DefaultListableBeanFactory: 综合上面所有功能,主要是对 Bean 注册后的处理 。

四、总结

我们基本上已经了解了 Spring 是使用 BeanFactory 将我们的 Bean 管理了起来。GenericApplicationContext 通过持有了一个 DefaultListableBeanFactory 作为 BeanFactory 的默认实现。后续我们就要继续探索 Spring 是如何将我们的 Bean 加载到 BeanFactory 中去的。


程序员的核心竞争力其实还是技术,因此对技术还是要不断的学习,关注 “IT 巅峰技术” 公众号 ,该公众号内容定位:中高级开发、架构师、中层管理人员等中高端岗位服务的,除了技术交流外还有很多架构思想和实战案例,作者是 《 消息中间件 RocketMQ 技术内幕》 一书作者,同时也是 “RocketMQ 上海社区”联合创始人,曾就职于拼多多、德邦等公司,现任上市快递公司架构负责人,主要负责开发框架的搭建、中间件相关技术的二次开发和运维管理、混合云及基础服务平台的建设。

发布于: 刚刚阅读数: 2
用户头像

一线架构师、二线开发、三线管理 2021.12.07 加入

Redis6.X、ES7.X、Kafka3.X、RocketMQ5.0、Flink1.X、ClickHouse20.X、SpringCloud、Netty5等热门技术分享;架构设计方法论与实践;作者热销新书《RocketMQ技术内幕》;

评论

发布
暂无评论
Spring容器的核心组件_IT巅峰技术_InfoQ写作平台