# Spring全攻略 **Repository Path**: r0ad/SpringGuide ## Basic Information - **Project Name**: Spring全攻略 - **Description**: 源码下面无秘密,这是程序员的口头禅。对于强大而且设计优秀的Spring框架也是这样的,在基础代码层层堆叠之下,Spring成为了一个非常流行的框架。 - **Primary Language**: Java - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-04 - **Last Updated**: 2024-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring6全攻略 源码下面无秘密,这是程序员的口头禅。对于强大而且设计优秀的Spring框架也是这样的,在基础代码层层堆叠之下,Spring成为了一个非常流行的框架。 Spring6框架的开发者们通过层层设计和封装打造了一个功能如此之多而兼容性非常好的框架。这也是解构这个框架难点,而通过理解整个框架功能的实现也差不多了解了整个Spring的生态,甚至是整个java开发生态的大部分知识。 ## Spring6框架包含哪些内容 通过SpringFramework6的源码可以看到,Spring包含如下几个模块: - `spring-aop`:提供了面向切面编程(AOP)的支持,允许在代码中分离横切关注点。 - `spring-aspects`:包含了用于实现 AOP 的AspectJ 集成和 weaving 功能。 - `spring-beans`:是 Spring 框架的核心模块之一,提供了对 JavaBean 的配置和管理。 - `spring-context`:提供了应用程序上下文的管理和配置,包括依赖注入和上下文的生命周期。 - `spring-context-indexer`:用于支持 Spring Context 的索引和搜索功能。 - `spring-context-support`:提供了一些额外的上下文支持,如缓存、事件发布和监听器等。 - `spring-core`:是 Spring 框架的基础模块,包含了一些核心的工具和类。 - `spring-core-test`:是 Spring 核心模块的测试支持。 - `spring-expression`:提供了一种强大的表达式语言,用于在配置文件和注解中解析和操作对象。 - `spring-instrument`:用于在应用程序运行期间动态检测和修改类的行为。 - `spring-jcl`:提供了 JCL(Jakarta Commons Logging)的集成和日志管理。 - `spring-jdbc`:提供了对 JDBC 数据库操作的简化和封装。 - `spring-jms`:用于与 JMS(Java Message Service)消息队列的集成。 - `spring-messaging`:是一个通用的消息传递抽象和实现。 - `spring-orm`:提供了对 ORM(Object Relational Mapping)框架的集成支持。 - `spring-oxm`:是 Spring Object/Relational Mapping(ORM)模块的一部分。 - `spring-r2dbc`:用于与 Reactive Relational Database Connectivity(反应式关系型数据库连接)的支持。 - `spring-test`:提供了用于测试 Spring 应用程序的工具和类。 - `spring-tx`:提供了对事务管理的支持。 - `spring-web`:是 Spring 框架的 Web 模块,提供了 Web 应用程序的开发支持。 - `spring-webflux`:用于构建反应式 Web 应用程序。 - `spring-webmvc`:是传统的 Spring MVC 框架,用于构建 Web 应用程序。 - `spring-websocket`:用于实现 WebSocket 通信。 这些模块基本就是Spring6框架的全部核心了。 ## Spring6框架如何深入了解 如何深入了解Spring框架呢? 一个很常用的办法就是通过使用到的api结合源码来分析和理解。api给程序员一个直观的体验,这个api是什么,就有什么功能。 当想要理解原理的时候,就可以结合源码来来了解原理和实现方式。源码下面无秘密。 另外一方面就是通过实现接口或者仿写接口来更加深入的理解源码当中的原理。为什么要这样写而不是其它方式呢?性能还是复用?通过实现接口肯定能学到更多东西。 这里就有一个大概的学习Spring6框架的模板了。 - 编写demo使用api - 阅读api的源码和实现 - 编写api的实现 - 编写单元测试 以Sping6框架中核心类`org.springframework.beans.factory.BeanFactory`为例说明整个研究和学习过程。 接口`org.springframework.beans.factory.BeanFactory#getBean`,它的主要功能如下: - 返回指定 bean 的一个实例,该实例可以是共享的或独立的。 - 这种方法允许 Spring BeanFactory 用作 Singleton 或 Prototype 设计模式的替代品。在 Singleton bean 的情况下,调用者可能会保留对返回对象的引用。 - 将别名转换回相应的规范 bean 名称。 - 如果在该工厂实例中找不到该 bean,则将向父工厂询问。 - 编写使用demo ```java package io.yulin.learn.spring.s100; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.BeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.stereotype.Component; /** * BeanFactory获取Bean使用demo * @author r0ad * @since 1.0 */ @SpringBootApplication @Slf4j public class BeanFactoryGetBean { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(BeanFactoryGetBean.class, args); log.info("当前上下文是BeanFactory {}",context instanceof BeanFactory); ComponentDemo1 componentDemo1 = (ComponentDemo1) context.getBean("ComponentDemo1"); // 测试获取到的bean的接口 componentDemo1.test(); // 关闭应用 context.close(); } } @Component("ComponentDemo1") @Slf4j class ComponentDemo1 { public void test() { log.info("ComponentDemo1 test"); } } ``` 输出的结果如下。可以看到`ConfigurableApplicationContext`实现了`BeanFactory`的`getBean`接口。通过`context.getBean("ComponentDemo1")`获取到的bean就是`ComponentDemo1`。而且可以直接调用`test`方法。 ```shell 当前上下文是BeanFactory true ComponentDemo1 test ``` 我们可以通过一个ConcurrentHashMap来维护bean的实例。通过这个Map实现`getBean`方法。 ```java package io.yulin.learn.spring.s100; import org.springframework.beans.factory.BeanCreationException; import java.util.concurrent.ConcurrentHashMap; /** * 实现 BeanFactory 接口的getBean方法,由于BeanFactory有很多接口,此处演示就没有直接implements BeanFactory * @author nine * @since 1.0 */ public class BeanFactoryDemoImpl { private ConcurrentHashMap beans = new ConcurrentHashMap<>(); public Object getBean(String name) throws BeanCreationException { if (beans.containsKey(name)) { return beans.get(name); } else { throw new BeanCreationException("Bean not found: " + name); } } // 添加方法用于向 ConcurrentHashMap 中添加 bean public void registerBean(String name, Object bean) { beans.put(name, bean); } // 添加方法用于从 ConcurrentHashMap 中移除 bean public void removeBean(String name) { beans.remove(name); } } ``` 编写了一个单元测试并且测试通过。 ```java package io.yulin.learn.spring.s100; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; /** * 自定义getBean实现的单元测试 * @author nine */ public class TestDemoImplGetBean { @Test public void testDemoImplGetBean() { BeanFactoryDemoImpl beanFactoryDemo = new BeanFactoryDemoImpl(); beanFactoryDemo.registerBean("test", new ComponentDemo1()); Object test = beanFactoryDemo.getBean("test"); boolean instanceCheck = test instanceof ComponentDemo1; assertThat(instanceCheck).isTrue(); ((ComponentDemo1) test).test(); } } ``` 实际实现接口`org.springframework.beans.factory.BeanFactory#getBean`要复杂的多。需要实现上文提到的全部功能。以下是一个Spring6框架中的实现。 ```java /** * 从IoC容器中获取指定名称的bean实例。 * * @param name 要获取的bean的名称,可能包含工厂Bean引用前缀 * @return 根据名称创建或获取的bean实例 * @throws BeansException 若在获取、创建或初始化bean过程中发生异常时抛出 */ public Object getBean(String name) throws BeansException { // 首先处理并转换传入的bean名称(例如移除FactoryBean前缀等) String beanName = BeanFactoryUtils.transformedBeanName(name); // 从容器内部存储的bean定义集合中查找指定名称的bean实例 Object bean = this.beans.get(beanName); // 如果未找到该bean,则抛出 NoSuchBeanDefinitionException 异常 if (bean == null) { throw new NoSuchBeanDefinitionException( beanName, "Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]"); } // 检查是否是工厂Bean引用,并确保它实际上是FactoryBean类型 // 若不是工厂Bean却被尝试作为工厂Bean引用,抛出异常 if (BeanFactoryUtils.isFactoryDereference(name) && !(bean instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, bean.getClass()); } // 如果当前bean是一个FactoryBean,并且调用者没有显式要求获得FactoryBean本身, // 则通过调用FactoryBean.getObject()方法来获取由其生成的bean实例 if (bean instanceof FactoryBean factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { try { // 获取FactoryBean所生产的对象实例 Object exposedObject = factoryBean.getObject(); // 如果FactoryBean返回null,则抛出异常 if (exposedObject == null) { throw new BeanCreationException(beanName, "FactoryBean exposed null object"); } // 返回由FactoryBean生成的对象实例 return exposedObject; } catch (Exception ex) { // 若在调用FactoryBean.getObject()过程中出现任何异常,包装成BeanCreationException抛出 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); } } else { // 如果bean不是FactoryBean,或者请求的是FactoryBean自身,直接返回bean实例 return bean; } } ``` 通过上述整个过程的实战和源码分析,可以对Spring6的核心功能有一个更加清晰的了解和感悟。 ## Spring6框架需要了解哪些内容 通过Spring6框架的官方文档可以找到大致的框架。 Spring的文档一直以来都是非常清晰的。尤其是在无数次迭代之后更能体现Spring的设计之美。 其中Spring6框架大致分为6个大类,每个大类对应很多小类和技术细节。 这6个大类分别是: **CORE 核心技术:** Spring 框架的核心技术包括 IoC 容器、依赖注入、AOP、事件机制等。IoC 容器提供了对象的生命周期管理和依赖关系的维护,依赖注入通过配置或注解的方式实现对象之间的解耦,AOP 支持面向切面编程,而事件机制则允许应用程序中的组件之间进行事件通知和处理。 **TESTING 测试:** Spring 框架提供了丰富的测试支持,包括单元测试、集成测试、模拟对象、测试数据准备等功能。通过 Spring 的测试框架,开发人员可以方便地编写和运行各种类型的测试,并且能够与 Spring 应用程序的其他部分无缝集成。 **Data Access 数据访问:** Spring 的数据访问层提供了对 JDBC、ORM 框架(如 Hibernate、MyBatis)、NoSQL 数据库(如 MongoDB、Redis)等的支持,同时也提供了事务管理、数据源管理、数据访问模板等功能,简化了数据访问层的开发。 **Web Servet:** 在 Web Servlet 领域,Spring 框架提供了对 Servlet、JSP、WebSocket、Web MVC 等的支持,包括处理请求、视图解析、控制器、拦截器等功能,同时也提供了 RESTful Web 服务的开发支持。 **Web Reactive:** Spring Web Reactive 则是针对响应式编程模型提供支持,包括非阻塞 I/O、异步处理、反应式流等特性,同时提供了 WebFlux、WebClient、WebSocket、RSocket 等组件,用于构建响应式的 Web 应用程序。 **Integration 集成:** Spring 提供了对 REST Clients、JMS、JCA、JMX、Email、Tasks、Scheduling、Caching、Observability、JVM Checkpoint Restore 等集成功能的支持,使得应用程序可以方便地与外部系统集成,并且具备了更好的可观察性和可扩展性。 ### **CORE 核心技术:** - IoC Container(控制反转容器):Spring 的核心功能之一,通过 IoC 容器管理和组织应用程序中的对象及其依赖关系。它负责实例化、配置和管理这些对象,以及处理它们之间的依赖注入。 - Events(事件):Spring 的事件机制允许应用程序中的组件发送和接收事件。这种松耦合的通信方式可以用于实现模块之间的交互和触发异步操作。 - Resources(资源加载):Spring 提供了统一的资源加载机制,使得应用程序可以轻松地访问不同类型的资源,如文件、类路径资源、URL 等。 - i18n(国际化):Spring 提供了国际化支持,使得应用程序能够根据用户的语言环境展示不同的文本消息和格式化数据。 - Validation(验证):Spring 的验证框架提供了一种方便的方式来验证表单数据和其他输入数据的有效性。它支持各种验证规则和自定义验证器。 - Data Binding(数据绑定):Spring 提供了强大的数据绑定机制,可以将请求参数、表单数据等与 Java 对象进行绑定,简化了数据传输和处理的过程。 - Type Conversion(类型转换):Spring 的类型转换机制可以自动将一种类型的值转换为另一种类型,使得应用程序在处理不同数据类型时更加灵活和方便。 - SpEL(Spring 表达式语言):SpEL 是一种强大的表达式语言,允许在运行时对对象图进行查询和操作。它可以在配置文件中使用,也可以在运行时通过编程方式使用。 - AOP(面向切面编程):Spring 的 AOP 支持通过代理机制实现横切关注点(如日志、事务管理等)的模块化开发。它通过切面、连接点和通知来实现对目标对象的增强。 - AOT(Ahead of Time Compilation,预编译):AOT 是 Spring 框架的一个最新功能,通过提前将 Spring 应用程序的字节码编译成本地机器代码,以提高应用程序的性能和启动速度。 以上是关于 Spring 框架中 CORE 核心技术的功能说明,它们共同构成了 Spring 的基础,并为开发者提供了很多有用的特性和工具。 ### **TESTING 测试:** - Mock Objects:Spring 允许创建和使用模拟对象(Mock Objects),这些对象可以替代真实的对象进行单元测试,以便更容易地隔离被测试的组件。 - TestContext Framework:Spring 的 TestContext 框架提供了一种统一的方式来加载和管理应用程序上下文,使得在测试中可以方便地使用 Spring 容器和其他功能。 - Spring MVC Test:Spring MVC Test 提供了对 Spring MVC 应用程序进行集成测试的支持,可以模拟 HTTP 请求和响应,验证控制器的行为和视图的渲染结果。 - WebTestClient:WebTestClient 是 Spring WebFlux 模块提供的用于测试 WebFlux 应用程序的客户端工具,可以进行异步、非阻塞的 Web 应用程序测试。 这些功能使得在 Spring 框架中进行单元测试、集成测试和端到端测试变得更加简单和高效。 ### **Data Access 数据访问:** - Transactions(事务):Spring 框架提供了强大的事务管理功能,支持声明式事务和编程式事务,以确保数据库操作的一致性和可靠性。 - DAO Support(DAO 支持):Spring 提供了对数据访问对象(Data Access Object)的支持,通过封装数据库访问逻辑到 DAO 中,简化了数据访问层的开发和维护。 - JDBC:Spring 对 JDBC(Java Database Connectivity)提供了高度集成的支持,通过 JDBC Template 等类,简化了数据库访问的代码编写,并处理了资源管理和异常处理等细节。 - R2DBC:Spring 通过支持 R2DBC(Reactive Relational Database Connectivity),使得在响应式应用程序中进行关系型数据库的异步操作更加便捷。 - O/R Mapping(对象关系映射):Spring 提供了强大的对象关系映射支持,通过框架内置的 ORM(Object-Relational Mapping)工具,将数据库表的记录映射为 Java 对象,方便进行对象的持久化与操作。 - XML Marshalling(XML 序列化):Spring 提供了对 XML 数据的序列化和反序列化支持,可以方便地将 Java 对象转换为 XML 格式或将 XML 转换为 Java 对象,用于处理 XML 数据的读写操作。 这些数据访问功能使得在 Spring 框架中进行数据持久化和操作变得更加简单、高效和可靠,提升了开发人员的生产力。 ### **Web Servet:** - Spring MVC:Spring MVC 是 Spring 框架中的 Web 模块,提供了基于模型-视图-控制器(MVC)设计模式的 Web 应用程序开发支持,用于构建灵活、可扩展的 Web 应用程序。 - WebSocket:Spring 框架支持 WebSocket 技术,可以实现全双工的通信方式,适用于需要实时性和互动性的 Web 应用程序开发。 - SockJS:SockJS 是一个 JavaScript 库,Spring 框架通过对 SockJS 的支持,可以实现在不同浏览器上对 WebSocket 的兼容性,确保更广泛的客户端支持。 - STOMP Messaging:STOMP(Simple Text Oriented Messaging Protocol)是一种简单文本导向的消息协议,在 Spring 框架中提供了对 STOMP 协议的支持,用于实现基于消息的应用程序通信。 这些功能为开发者提供了丰富的选择,使得在 Spring 框架中开发 Web 应用程序更加便捷、高效,并支持现代化的 Web 开发需求。 ### **Web Reactive:** - Spring WebFlux:Spring WebFlux 是 Spring 框架中的响应式编程模块,基于 Reactor 库提供了一种非阻塞的、异步的编程模型,用于构建高性能、可扩展的响应式 Web 应用程序。 - WebClient:Spring WebClient 是一个非阻塞的、异步的 HTTP 客户端,用于在 WebFlux 应用程序中进行远程服务调用,支持响应式流处理和各种协议。 - WebSocket:Spring 框架通过对 WebSocket 技术的支持,可以实现全双工的通信方式,用于构建实时的、互动性强的 Web 应用程序。 - RSocket:RSocket 是一种可扩展的、异步的、多种传输协议的消息通信协议,Spring 框架提供了对 RSocket 的支持,用于构建分布式系统中的可靠通信。 这些功能使得在 Spring 框架中开发响应式的 Web 应用程序更加便捷、高效,并能够处理大量并发请求和实时数据交互。它们适用于需要高性能、可伸缩性和实时性的现代 Web 应用程序开发。 ### **Integration 集成:** - REST Clients:Spring 框架提供了对 RESTful 服务的客户端支持,可以方便地进行 REST API 的调用和交互,实现与其他服务的集成。 - JMS:Spring 对 Java Message Service(JMS)提供了集成支持,用于在分布式系统中进行异步消息传递,实现应用程序之间的解耦和通信。 - JCA:Spring 框架支持 Java Connector Architecture(JCA),用于与企业信息系统(如 ERP、CRM 等)进行连接和集成,实现企业级应用程序的互操作性。 - JMX:Spring 提供了对 Java Management Extensions(JMX)的支持,用于监控和管理应用程序的运行时状态,实现应用程序的监控和远程管理。 - Email:Spring 框架提供了发送和接收电子邮件的功能支持,简化了电子邮件服务的集成和操作,用于实现邮件通知和交互功能。 - Tasks:Spring 支持异步任务执行,通过 TaskExecutor 接口和相关类,可以实现异步任务的调度和执行,提升应用程序的性能和响应速度。 - Scheduling:Spring 提供了任务调度的功能支持,可以通过注解或配置的方式实现定时任务的执行,用于处理周期性任务和定时作业。 - Caching:Spring 框架提供了对缓存的抽象和支持,可以通过缓存注解实现方法级别的缓存,提升应用程序的性能和响应速度。 - Observability:Spring 支持应用程序的可观察性,包括日志记录、指标监控、跟踪和分析等功能,帮助开发者了解应用程序的运行状态并快速定位问题。 - JVM Checkpoint Restore:Spring 支持 JVM 的检查点恢复,可以在应用程序异常时保存当前状态,并在恢复时恢复到之前的状态,减少数据丢失和影响范围。 这些功能使得在 Spring 框架中集成其他系统或者扩展变的十分容易。 ## 总结 通过源码,我们可以看到Spring6框架的核心和组成。 Spring框架的核心技术包括IoC容器、依赖注入、AOP等,为应用程序提供对象生命周期管理、解耦和面向切面编程等功能;同时,它拥有丰富的测试支持,简化了单元测试、集成测试的编写与执行;在数据访问层面,Spring全面支持多种数据库技术,并提供了事务管理、模板类等工具;Web层方面,Spring不仅涵盖了Servlet/JSP/Web MVC的传统Web开发,还支持响应式编程模型如WebFlux;此外,Spring还具备强大的集成能力,方便与外部系统交互并实现可观察性和扩展性。 在“Spring6全攻略”中,后续将通过如下的流程来完成整个Spring6的攻略。 - 编写demo使用api - 阅读api的源码和实现 - 编写api的实现 - 编写单元测试 ## 参考资料 ### 视频 - 黑马程序员Spring视频教程,深度讲解spring5底层原理 ### 文档 - Spring 6 javadoc - Spring 6 参考文档 - Spring 6 源码 ## 关于作者 来自一线全栈程序员nine的八年探索与实践,持续迭代中。欢迎关注公众号“雨林寻北”或添加个人卫星codetrend(备注技术)。