你好,这里是codetrend专栏“Spring6全攻略”。
控制反转(Inversion of Control, IoC)是一种软件设计原则,它将传统的程序设计中的控制权从应用程序代码转移到框架或容器,从而实现了松耦合和更好的可维护性。
在控制反转的概念中,应用程序的组件不再负责自己的创建和管理,而是交给外部容器来负责。这样做的好处是降低了组件之间的依赖关系,提高了代码的灵活性和可测试性。
Spring框架是一个经典的IoC容器,它通过依赖注入(Dependency Injection, DI)的方式实现了控制反转。在Spring中,开发者只需要定义组件及其依赖关系,而框架负责实例化和管理这些组件,将依赖关系注入到需要的地方。
依赖注入(Dependency Injection, DI)是IoC的一种专门形式,其中对象仅通过构造函数参数、工厂方法参数或在对象实例被构建后设置的属性来定义它们的依赖关系(即与之协同工作的其他对象)。接着,在创建bean时,IoC容器会注入这些依赖项。这一过程本质上是对bean自身直接控制其依赖项的实例化或定位方式的反转(因此得名“控制反转”),通常采用直接构造类或类似服务定位器模式的机制。
整个过程用mermaid流程图表示如下:
graph LR A[应用程序] --> B[IoC容器] B --> C[创建Bean] C --> D[实例化Bean] D --> E[解析依赖关系] E --> F{依赖注入} F -- 是 --> G[通过构造函数参数、工厂方法参数或属性设置注入依赖项] F -- 否 --> H[使用服务定位器等机制定位依赖项]
org.springframework.beans
和 org.springframework.context
包构成了Spring框架IoC容器的基础。关于IoC的代码实现都是放在这里面的。
BeanFactory
接口提供了一个高级配置机制,能够管理任何类型的对象。而ApplicationContext
是 BeanFactory
的一个子接口,并增加了以下功能:
- 更易于集成Spring的AOP特性
- 消息资源处理(用于国际化)
- 事件发布
- 应用层特定上下文,例如Web应用程序中使用的WebApplicationContext
简而言之,BeanFactory
提供了配置框架和基本功能,而ApplicationContext
则扩展了更多企业级特有的功能。ApplicationContext
完全包含了BeanFactory
的所有功能。
在Spring中,构成应用程序核心并由Spring IoC容器管理的对象被称为bean。
bean是由Spring IoC容器实例化、组装和管理的对象。除此之外,bean只是应用中的众多对象之一。bean及其之间的依赖关系体现在容器所使用的配置元数据中。
SpringBean的历史渊源
Jakarta EE中定义了一个Enterprise Beans。由于Spring6框架和Jarkata EE中的规范是息息相关的,通过对比的方法来一探究竟。
Spring Bean 是指在Spring框架中由IoC容器管理的对象实例,也被称作“Spring组件”。这些Bean构成了应用程序的主要部分,负责承载业务逻辑和服务功能。
Spring Bean的特点如下:
- 容器管理:Spring IoC(控制反转)容器负责Bean的生命周期管理,包括创建、初始化、装配依赖、销毁等一系列操作。
- 依赖注入:Bean之间的依赖关系通过依赖注入(Dependency Injection,DI)来建立,容器负责将所需的依赖项注入到Bean中,而不是由Bean自身去寻找或创建这些依赖。
- 配置元数据:Spring Bean的定义和配置信息通常存储在XML配置文件、Java配置类或者注解中,这些配置元数据指导了IoC容器如何创建和管理Bean。
- 作用域:Spring Bean有多种作用域,如Singleton(单例)、Prototype(原型)、Request、Session、Application和WebSocket等,不同的作用域决定了Bean实例在应用程序中的创建和共享策略。
- 生命周期:Spring Bean拥有完整的生命周期,允许开发者通过实现特定的接口(如InitializingBean、DisposableBean或使用@PostConstruct/@PreDestroy注解)来自定义初始化和销毁逻辑。
- 可扩展性:通过BeanPostProcessor和FactoryBean等扩展点,可以进一步自定义Bean的创建过程和行为。
- 松耦合:通过依赖注入实现松耦合,使得各组件间相互独立,更容易维护和替换。
- 面向切面编程(AOP):Spring Bean能够无缝地与Spring的AOP机制相结合,支持诸如事务管理、日志记录、权限检查等横切关注点的统一处理。
- 自动装配:Spring支持自动装配功能,可以通过@Autowired注解或其他机制自动匹配并注入相应的依赖服务。
Jakarta EE 中的EJB(Enterprise JavaBeans)是一种用于开发企业级分布式应用程序的标准组件模型,它为开发人员提供了封装业务逻辑并在多个客户端之间复用的能力。
EJB主要具有如下特点:
- 容器管理:EJB运行在EJB容器中,容器负责管理Bean的生命周期、安全、事务、并发、资源池化等非功能性需求,减轻了开发者的工作负担。
- 事务管理:EJB提供全面的事务支持,包括全局事务(Global Transactions)和局部事务(Container-Managed Transactions, CMT),能够跨多个数据库或消息队列资源进行事务管理。
- 安全性:EJB容器支持基于角色的安全性,开发者可以在EJB级别定义访问控制策略,确保只有授权用户或角色才能访问特定的业务服务。
- 消息驱动:消息驱动Bean可以监听JMS(Java Message Service)消息,实现异步处理和解耦,适用于高性能的消息传递场景。
- 持久化支持:实体Bean特别设计用于映射数据库表,提供了ORM(对象关系映射)的功能,使得业务对象可以自动持久化至数据库。
- 远程访问:EJB支持远程调用,客户端可以通过RMI(Remote Method Invocation)协议访问部署在服务器上的EJB组件。
与Spring6框架对比,EJB的一些复杂性和重量级特性逐渐显得过重,尤其是在易用性、测试友好度以及性能方面。
Spring6通过提供更为简洁的编程模型和灵活的事务管理等功能,一定程度上替代了EJB在某些场景下的应用。
Spring6通过组件项目的方式提供了对EJB的替代。Spring只提供最基础的核心功能。比如spring-jms
用于与 JMS(Java Message Service)消息队列的集成、 spring-tx
提供了对事务管理的支持。
所以Spring6的设计在于轻量级、组件可选的方式来完成了一个又一个企业级应用的搭建。
说说什么是SpringBean
Spring IoC容器管理一个或多个bean。这些bean是根据您提供给容器的配置元数据创建的(例如,以XML <bean/>
定义的形式)。
在容器内部,这些bean定义被表示为BeanDefinition对象,其中包含(除其他信息外)以下元数据:
- 带包限定名的类名:通常是指定bean的实际实现类。
- Bean行为配置元素,描述了bean在容器中应该如何表现(作用域、生命周期回调等)。
- 对于bean完成其工作所必需的其他bean的引用。这些引用也被称为协作者或依赖项。
- 其他配置设置,用于在新创建的对象上设置属性——例如,在管理连接池的bean中设置池大小限制或使用连接数。
这些元数据转换成构成每个bean定义的一组属性。下表描述了这些属性:
属性 | 描述章节 |
Class | 实例化Bean |
Name | 命名Bean |
Scope | Bean作用域 |
Constructor arguments | 依赖注入 |
Properties | 依赖注入 |
Autowiring mode | 自动装配协作者 |
Lazy initialization mode | 懒加载Bean |
Initialization method | 初始化回调 |
Destruction method | 销毁回调 |
表1. Bean定义属性
通过Bean定义属性这张表格可以看出Bean的全景图,而Spring6基于此提供了一个完整的实现方案。
除了包含创建特定bean所需信息的bean定义之外,ApplicationContext实现还允许注册由用户在容器外部创建的现有对象。这通过访问ApplicationContext的BeanFactory来实现,即调用getBeanFactory()方法,该方法返回DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(..)
和registerBeanDefinition(..)
方法支持这种注册功能。然而,典型的应用程序通常仅使用通过常规bean定义元数据定义的bean。
注意:bean元数据和手动提供的单例实例需要尽早注册,以便容器在自动装配和其他内省步骤中正确地解析它们。
虽然在一定程度上支持覆盖现有元数据和现有单例实例,但在运行时(与对工厂的实时访问同时)注册新的bean并未得到官方支持,这可能会导致并发访问异常、bean容器状态不一致,或者两者兼有。
说说 Spring IoC容器
org.springframework.context.ApplicationContext
接口代表了Spring的IoC(控制反转)容器,并负责bean的实例化、配置和组装。该容器通过读取配置元数据获取关于需要实例化、配置和组装哪些对象的指令。
这些配置元数据可以以XML、Java注解或Java代码的形式表示,它允许你明确表达组成应用程序的对象以及这些对象之间的丰富依赖关系。
Spring提供了多个ApplicationContext
接口的实现版本。在独立应用程序中,通常会创建一个ClassPathXmlApplicationContext
或FileSystemXmlApplicationContext
实例。
尽管XML是定义配置元数据的传统格式,但可以通过提供少量XML配置来声明性地启用对Java注解或代码作为元数据格式的支持,从而指导容器使用这些额外的元数据格式。
以下mermaid流程图简单展示了Spring工作过程。业务类与配置元数据相结合,使得在Spring容器ApplicationContext
被创建并初始化后,得到的是一个完全配置好且可执行的系统或应用程序。
graph LR A[业务类POJO] --> C[Spring容器ApplicationContext] B[配置元数据Configuration Metadata] --> C C --产生--> D[可执行的系统/应用程序]
说说配置元数据(Configuration Metadata)
Spring的Configuration Metadata是指一组用于描述和指导Spring IoC(控制反转)容器如何创建、配置和装配应用中各个对象(即所谓的“bean”)的信息。这种元数据传统上是以一种直观且简洁的XML格式提供的,但也可以采用Java注解或纯Java代码的形式表示。
Configuration Metadata包含了如下关键信息:
- Bean定义: 对象的类型、名称、构造器参数、属性值和依赖关系等,这些信息告诉Spring容器如何实例化对象。
- 装配指示: 如何将一个bean与其他bean关联起来,包括设置属性值、引用其他bean、注入集合元素等。
- 生命周期回调方法: 定义在bean的生命周期中何时调用特定的方法,例如初始化后(@PostConstruct)或销毁前(@PreDestroy)。
- 容器配置: 容器自身的配置,如自动扫描哪些包以发现组件、启用特定的特性(如自动装配或AOP代理)等。
在XML配置文件中,配置元数据表现为<bean>
元素及其内部属性和嵌套元素;在Java配置中,配置元数据则通过标注了@Configuration
的类以及标注了@Bean
的方法来定义。
Spring Configuration Metadata是程序员向Spring IoC容器传达应用程序对象结构和依赖关系的蓝图,是Spring框架动态装配和管理对象的基础。通过解析和应用这些配置元数据,Spring IoC容器能够在运行时生成一个完全配置好并准备就绪的应用程序对象图。
以下是一个基于xml的Spring配置文件的示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>