Spring是如何设计IOC容器的?BeanFactory ApplicationContext

2024-06-18 17:52

本文主要是介绍Spring是如何设计IOC容器的?BeanFactory ApplicationContext,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

BeanFactory是Spring框架中最底层的接口,用于实例化、配置和管理bean。它使用控制反转(IOC)模式,将对象的创建、管理和装配的职责从应用程序代码中转移给Spring容器。这样,应用程序代码就无需关心对象如何创建和装配,只需从容器中获取所需的对象即可。关于BeanFactory和Bean的实例化,有几点需要明确:

  1. 延迟初始化:BeanFactory默认采用延迟初始化的策略。这意味着当你创建一个BeanFactory实例时,它并不会立即实例化容器中定义的所有Bean。相反,它会等待直到某个Bean第一次被请求时,才会实例化该Bean。这种策略可以提高应用程序的启动速度,因为不是所有的Bean在启动时就都需要被实例化。
  2. 依赖注入:当BeanFactory被要求实例化一个Bean时,它会查看该Bean的依赖关系,并根据配置自动装配这些依赖。这通常通过自动装配(如通过构造函数、setter方法或字段注入)或手动装配(在XML配置文件中或通过Java配置类指定)来完成。
  3. 作用域:Spring容器中的Bean有不同的作用域(如单例、原型、请求、会话等)。BeanFactory会根据Bean的作用域来决定如何实例化和管理Bean。例如,单例Bean在整个容器生命周期内只会被实例化一次,而原型Bean每次被请求时都会实例化。
  4. 生命周期管理:除了实例化和依赖注入外,BeanFactory还负责管理Bean的生命周期。BeanPostProcessor 与 BeanFactoryPostProcessor 。

Spring 设计了两个接口用以表示容器:BeanFactory && ApplicationContext。BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

1、BeanFactory 就是个 HashMap,Key 是 beanName,Value 是 Bean 实例。Spring里面最底层的接口:读取bean配置文档,包含了各种Bean的定义,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”,是 Spring 应用上下文。他继承了多个接口,因此具备了更多的功能:

1、EnvironmentCapable:为applicationContext声明了获取激活profile、默认profile 方法的功能,也即Environment这个接口代表应用运行时的环境。
2、MessageSource:支持消息的参数化和国际化
3、ApplicationEventPublisher:事件发布
4、ResourcePatternResolver:统一的资源文件访问方式
5、ListableBeanFactory:继承了BeanFactory,实现了枚举方法列举出当前BeanFactory中所有的bean对象而不必根据name一个一个的获取。
6、HierarchicalBeanFactory:是一个具有层级关系的Bean 工厂,拥有属性parentBeanFactory:当获取 Bean对象时,如果当前BeanFactory中不存在对应的bean,则会访问其直接 parentBeanFactory 以尝试获取bean 对象。载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

2、BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

3、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:在BeanFactory中,需要手动注册BeanPostProcessor和BeanFactoryPostProcessor。这意味着开发者需要显式地在代码中调用相关方法来完成注册过程。相比之下,ApplicationContext会自动注册BeanPostProcessor和BeanFactoryPostProcessor。这意味着开发者无需显式注册这些后处理器,Spring容器会在启动时自动完成这一过程。

在Spring框架中,BeanFactoryPostProcessor 是一个特殊的bean,允许你在Spring容器实例化bean之前修改或定制应用上下文中的bean定义。BeanFactoryPostProcessor 的主要应用场景包括添加或修改bean的属性、修改bean之间的依赖关系等。

在Spring容器的初始化过程中,特别是在refresh()方法中,会调用invokeBeanFactoryPostProcessors()方法来执行所有的BeanFactoryPostProcessor。下面是invokeBeanFactoryPostProcessors()方法的基本逻辑概述:

  1. 检测BeanFactoryPostProcessor bean:Spring首先会检查容器中已经注册的所有bean定义,找出所有实现了BeanFactoryPostProcessor接口的bean。
  2. 实例化BeanFactoryPostProcessor bean:对于检测到的每一个BeanFactoryPostProcessor bean,Spring会实例化它们。但是,因为BeanFactoryPostProcessor本身也是bean,所以它们的实例化也会受到Spring的生命周期管理。
  3. 排序:如果BeanFactoryPostProcessor实现了Ordered接口或标记了@Order注解,那么Spring会按照定义的顺序来调用它们。此外,如果BeanFactoryPostProcessor实现了PriorityOrdered接口,那么这些bean会具有更高的优先级,并在普通的Ordered bean之前被调用。
  4. 调用postProcessBeanFactory方法:对于每一个BeanFactoryPostProcessor实例,Spring会调用其postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法。这个方法允许你修改或定制传入的ConfigurableListableBeanFactory,这个对象代表了Spring IoC容器当前的内部状态。
  5. 继续容器初始化:在所有BeanFactoryPostProcessor被调用并处理完毕后,Spring容器会继续其初始化过程,包括实例化、依赖注入、调用初始化方法等步骤。

通过BeanFactoryPostProcessor,你可以获得对Spring IoC容器内部状态的控制,并在bean实例化之前修改bean定义。这种能力使得BeanFactoryPostProcessor在Spring的扩展性和灵活性方面发挥了重要作用。

在Spring框架中,BeanPostProcessor接口允许开发者在Spring IoC容器实例化bean后、初始化方法(如果有的话)调用前和调用后插入自定义的逻辑。这是Spring AOP(面向切面编程)功能的一部分,虽然BeanPostProcessor本身并不直接实现AOP,但它为AOP提供了基础。

以下是BeanPostProcessor在Spring中使用的步骤:

  1. 定义BeanPostProcessor:你需要实现BeanPostProcessor接口,并重写postProcessBeforeInitialization和postProcessAfterInitialization方法。这两个方法分别在bean的初始化方法(如@PostConstruct注解的方法或实现了InitializingBean接口中的afterPropertiesSet方法)调用之前和之后被调用。
public class CustomBeanPostProcessor implements BeanPostProcessor {  @Override  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  // 在bean的初始化方法之前执行的逻辑  System.out.println("Before initialization: " + beanName);  return bean;  }  @Override  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  // 在bean的初始化方法之后执行的逻辑  System.out.println("After initialization: " + beanName);  return bean;  }  
}
  1. 注册BeanPostProcessor:将你的BeanPostProcessor实现注册到Spring容器中。这可以通过XML配置或Java配置完成。
<bean class="com.example.CustomBeanPostProcessor" />
@Configuration  
public class AppConfig {  @Bean  public CustomBeanPostProcessor customBeanPostProcessor() {  return new CustomBeanPostProcessor();  }  // ... 其他bean的定义 ...  
}
  1. 使用:一旦BeanPostProcessor被注册到容器中,Spring就会在创建并初始化每个bean时自动调用它。你不需要在代码中显式地调用BeanPostProcessor。需要注意的是,BeanPostProcessor自身也会被当作一个bean来处理,这意味着BeanPostProcessor也会受到BeanPostProcessor链的影响。因此,在定义多个BeanPostProcessor时,需要注意它们之间的依赖关系和初始化顺序。

通过BeanPostProcessor,你可以对Spring容器中的bean进行拦截,并在bean的生命周期中的关键点上添加自定义逻辑。这对于诸如日志记录、安全检查、性能监控等横切关注点(cross-cutting concerns)非常有用。

在这里插入图片描述

这篇关于Spring是如何设计IOC容器的?BeanFactory ApplicationContext的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072694

相关文章

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

Java利用@SneakyThrows注解提升异常处理效率详解

《Java利用@SneakyThrows注解提升异常处理效率详解》这篇文章将深度剖析@SneakyThrows的原理,用法,适用场景以及隐藏的陷阱,看看它如何让Java异常处理效率飙升50%,感兴趣的... 目录前言一、检查型异常的“诅咒”:为什么Java开发者讨厌它1.1 检查型异常的痛点1.2 为什么说

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

Spring-DI依赖注入全过程

《Spring-DI依赖注入全过程》SpringDI是核心特性,通过容器管理依赖注入,降低耦合度,实现方式包括组件扫描、构造器/设值/字段注入、自动装配及作用域配置,支持灵活的依赖管理与生命周期控制,... 目录1. 什么是Spring DI?2.Spring如何做的DI3.总结1. 什么是Spring D

spring AMQP代码生成rabbitmq的exchange and queue教程

《springAMQP代码生成rabbitmq的exchangeandqueue教程》使用SpringAMQP代码直接创建RabbitMQexchange和queue,并确保绑定关系自动成立,简... 目录spring AMQP代码生成rabbitmq的exchange and 编程queue执行结果总结s

Java调用Python脚本实现HelloWorld的示例详解

《Java调用Python脚本实现HelloWorld的示例详解》作为程序员,我们经常会遇到需要在Java项目中调用Python脚本的场景,下面我们来看看如何从基础到进阶,一步步实现Java与Pyth... 目录一、环境准备二、基础调用:使用 Runtime.exec()2.1 实现步骤2.2 代码解析三、