每日音乐/前言
本篇我会以:spring存在的意义 ⇒ spring生态系统的认识 ⇒ 传统spring ⇒ 其他spring框架诞生的原因 的思路进行梳理(个人理解)。
Spring初认识
Spring是Java 企业级应用开发中最流行的框架,没有之一(应该吧),Spring与Java的关系就像是江苏和试卷,成都和男娘一样密不可分,许多 Java 开发者在构建企业级应用时都会优先考虑使用 Spring。
Spring 是为了解决 Java 企业级开发中存在的复杂性和开发效率问题而诞生的,具体来说,它主要解决以下几个问题:
- 耦合性和依赖管理:在传统的 Java 开发中,不同组件和模块之间往往存在较强的耦合。对象之间的依赖关系通常是硬编码在代码中的,导致系统的灵活性差,维护难度大。(人话:就是当一个模块的代码出错/要修改时,改了这个模块的代码后,又因为其他模块和该模块有关(共同实现某种功能),我们又要改其他模块的代码,很JB烦 )
- 企业级功能的繁琐开发:在构建企业级应用时,通常需要实现诸如事务管理、安全性、持久化等功能,而这些功能开发起来比较繁琐且容易出错。
- 面向切面编程(AOP)的需求:在大型系统中,开发者经常会遇到一些横切关注点,这些关注点跨越了应用程序的多个模块和组件,但与具体的业务逻辑无直接关联。在大型系统中,日志记录、权限控制、异常处理等是常见的横切关注点,如果在每个业务逻辑中都硬编码这些横切逻辑,会导致代码重复和难以维护。(人话:AOP将代码与业务逻辑分离,该用什么就拿出来用,而不是每次用的时候都要重新写)
- 配置和部署的繁琐性:传统的 Java 企业应用通常依赖复杂的配置和 XML 文件,配置和部署都相对繁琐且容易出错。
- 多种技术整合的困难:企业应用通常需要整合多种技术栈和框架(如数据库、消息队列、缓存、分布式系统等),而手动集成这些技术栈不仅耗时,还容易导致兼容性问题。
- 测试复杂性:在传统的 Java 开发中,编写单元测试和集成测试常常很复杂,尤其是依赖外部资源的类。
- 微服务架构的实现需求:随着企业应用规模的扩大,传统的单体架构越来越难以满足业务需求,而微服务架构能够提高系统的可扩展性和灵活性。(别问,我也不懂)
总之,Spring就是为了实现Java的工程化,为了让Java写起来更简单,更舒服,更放心。
Spring生态系统
Spring技术框架图
(要我看我也看不懂,网上我转了一圈,暂时没有发现又简洁又明朗的Spring生态系统介绍,属实难绷)
我将Spring的表面的层次分为:Spring 生态系统 ⇒ 框架 ⇒ 模块 ⇒ 组件 。(非官方,只是我自己为了记忆和梳理进行的分类,模块可是组件,组件也可以是模块,根据自己的理解分类)
(官网:https://spring.io/projects/spring-framework )
- Spring 生态系统:Spring 是一个广义的生态系统,包含了多个项目和工具,致力于简化 Java 应用开发的方方面面。
- 框架:框架是 Spring 生态系统的主要组成部分,每个框架都有特定的功能领域,是专门是为了解决不同的开发需求而开发的不同工具箱。eg:Spring Framework、Spring Boot等
- 模块:每个框架可能包含多个模块,用于处理更具体的功能,不同的框架可以有相同的组件,同时模块可以不依赖于框架,可以单独使用,就像工具箱中的工具。eg:Spring Framework中的模块包括 Spring Core、Spring AOP、Spring MVC等
- 组件:组件是模块的进一步细分,本篇不进行阐述。eg:Spring Core 模块中的组件:Beans、Context、Expression Language (SpEL)。
接下来会举几个主要的框架和模块。
常见框架与模块
就简单介绍几个,看看就得了。
常用框架:
- Spring Framework:核心框架,提供了依赖注入(DI)和面向切面编程(AOP),是Spring生态的基础。(我们通常所说的 Spring 就是指的是 Spring Framework)
- Spring Boot:用于简化Spring应用开发的框架,提供了自动配置和内置服务器等特性。
- Spring Cloud:为分布式系统提供解决方案,包括服务注册、负载均衡、配置管理等。
- Spring Data:用于简化数据访问层的开发,支持多种数据库和数据存储。
- Spring Security:为应用提供安全功能,如身份验证和授权。
- Spring Batch:批处理框架,用于处理大批量任务。
常见模块:
- Spring Core:提供了Spring框架的基本功能,如IoC容器。
- Spring MVC:构建基于Servlet的Web应用程序的模块。
- Spring JDBC:用于简化JDBC操作。
- Spring AOP:面向切面编程支持模块。
- Spring ORM:集成Hibernate、JPA等ORM工具。
- Spring WebFlux:用于构建反应式Web应用程序。
- Spring Session(独立模块):主要用于管理用户会话信息,特别是在分布式Web应用程序中。
Spring Framework 6 的模块化结构
小小的介绍一下Spring Framework官方模块划分的功能层(算是模块的小集合),最传统的Spring框架:
Spring Framework 6版本
- Core Container(核心容器)
- Beans:Spring 框架的核心模块,提供了 IoC(控制反转)和 DI(依赖注入)功能,通过
BeanFactory
和ApplicationContext
等接口来管理应用程序中的对象。 - Core:提供了 IoC 和 DI 的基础支持,其他模块也是基于 Core 模块的实现来管理对象的生命周期。
- Context:基于 Core 模块的更高级的容器,它扩展了 BeanFactory,支持事件机制、国际化(i18n)、AOP 等功能。
- Expression:用于 Spring 表达式语言(SpEL),可以在 XML 配置或注解中动态解析和计算值。
- JCL:Java Common Logging(JCL)提供了日志记录的接口,使开发者可以在不同的日志实现间进行选择。
- Beans:Spring 框架的核心模块,提供了 IoC(控制反转)和 DI(依赖注入)功能,通过
- Data Access/Integration(数据访问/集成)
- JDBC:简化数据库访问的模板类,如
JdbcTemplate
,用于处理传统的 JDBC 连接和操作。 - ORM:为主流 ORM 框架(如 Hibernate、JPA)提供了集成支持,便于使用 ORM 方式与数据库交互。
- OXM:对象 XML 映射模块,支持对象和 XML 之间的转换。
- R2DBC:响应式关系型数据库连接,用于与响应式关系型数据库进行交互。
- Transactions:提供了声明式事务管理,简化了事务处理逻辑。
- JMS:Java 消息服务模块,用于支持消息队列和异步消息传递。
- JDBC:简化数据库访问的模板类,如
- Web Servlet(Web模块)
- Web:为创建 Web 应用程序提供了基础支持。
- WebMVC:传统 Spring MVC 模块,用于构建基于 Servlet 的 Web 应用,支持控制器、视图解析、数据绑定等功能。
- WebFlux:响应式编程框架,基于 Reactor 实现的非阻塞、异步的 Web 框架。
- WebSocket:提供了 WebSocket 的支持,用于实现双向通信的实时应用。
- AOP 和 Aspects(面向切面编程)
- AOP:支持面向切面编程(AOP),可以在应用程序运行期间动态地将切面功能织入到目标对象中,实现如日志记录、事务管理等横切关注点的处理。
- Aspects:提供了声明式 AOP 支持,允许通过注解来实现 AOP 功能。
- Instrument(工具):该模块主要用于在应用中增加代理功能,通常用于支持 AOP 和与 JVM 代理相关的功能。
- Messaging(消息传递):提供了与消息传递相关的支持,特别是与 Spring Integration 和 Spring AMQP 等模块集成,用于处理异步消息传递。
- Test(测试):Spring 提供了丰富的测试支持,包括对 JUnit 和 TestNG 的支持,用于帮助开发者编写单元测试和集成测试,简化了 Spring 应用的测试过程。
Spring核心设计思想
Spring的最核心部分是控制反转(IoC)和面向切面编程(AOP)。
控制反转(IoC)
看了上面的一些东西,估计已经有些劝退了,虽然Spring生态中的东西不少,但实际上Spring就是一个空箱子,等着你放东西进去,然后就可以实现不同的功能。准确来说:
Spring是包含了众多工具方法的IoC容器(空箱子,在 Spring 框架中,所有模块的核心组件(对象)都可以由 IoC 容器管理)。Spring通过依赖注入来管理对象及其依赖关系。脱离Spring解释一下几个名词:
- IoC(Inversion of Control,控制反转):控制反转是一种将对象的控制权从应用程序代码中“反转”给框架的设计思想。传统开发中,应用程序主动创建和管理依赖对象,而在IoC中,这种“控制权”被反转:对象的创建、管理、和依赖关系的维护都交由IoC容器处理,应用代码只需定义需要的依赖。
- DI(Dependency Injection,依赖注入):依赖注入是实现IoC的常用方式。DI的核心是“注入”依赖:在对象初始化时,将所需的依赖对象传递给它,而不是在对象内部直接创建依赖。
- 依赖:依赖是指一个类(或模块)需要另一个类(或模块)来合作完成某项功能的情况。也就是说,一个对象的正常工作需要另一个对象的支持,这种关系就叫做依赖。
举个例子:
class B {
public void doSomething() {
System.out.println("B is doing something");
}
}
class A {
private B b;
// 使用构造函数注入B类依赖
public A(B b) {
this.b = b;
}
public void performTask() {
b.doSomething();
}
}
//类A依赖于类B,类A需要类B的支持才能完成它的功能(即performTask方法)。
//类A通过调用类B的doSomething方法来完成任务。
public class Main {
public static void main(String[] args) {
B b = new B(); // 由外部创建B的实例
A a = new A(b); // 将B的实例注入给A
a.performTask();
}
}
//A类不再自己创建B类,而是由外部将B类的实例“注入”给A。
//这种方式实现了控制反转,因为A类的依赖管理权不再在自己手中,而是在外部代码(或框架)中完成。
不采用控制反转
class B {
public void doSomething() {
System.out.println("B is doing something");
}
}
class A {
private B b;
// 直接在A类内部实例化B类
public A() {
this.b = new B(); // A类直接创建B的实例
}
public void performTask() {
b.doSomething();
}
}
public class Main {
public static void main(String[] args) {
A a = new A(); // 直接创建A的实例
a.performTask();
}
}
在这个例子中,A类不再通过构造函数接收B类的实例,而是直接在自己的构造函数中创建了B类的实例。这种方式下,A类对B类的依赖是强耦合的,A类的实例直接控制B的创建与生命周期。
问题和缺点
-
耦合度高:A类与B类紧密耦合,A类不再灵活,如果需要使用不同的B实现(比如替换成另一个版本的A类),A类的代码必须修改。
-
不易扩展:如果有多个不同的B类实现,比如一个新的B的子类B2,则很难在不修改A类代码的情况下进行替换。扩展性较差。
-
难以测试:在单元测试中,A类会直接创建B类的实例,因此无法注入一个模拟的B类。这增加了测试的难度,因为每次测试A时都必须真实创建B。
这种写法虽然简单直接,但缺乏灵活性和可维护性。依赖注入的方式可以使代码更具可测试性、灵活性和可扩展性,从而降低类之间的耦合。
而在Spring中我们把控制权给了Spring,Spring 会帮我们管理所有的对象(Bean)。(也就是说在Spring中如果在A类中调用B类中的方法不用new A了,因为Spring会帮我们做的)
面向切面编程(AOP)
面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它关注程序中的“横切关注点”。横切关注点指的是在多个模块中都需要的通用功能(就相当于你每次吃饭,吃的饭每次可能不同,但都要筷子,此时筷子就是横切关注点),比如日志记录、权限控制、事务管理、异常处理等。传统的面向对象编程(OOP)通常关注“类”的概念,将代码封装在类和方法中,而AOP则允许在不改变业务逻辑的情况下,将这些通用功能分离出来并动态地加入到程序中。
AOP的主要思想是将“关注点”分离,尤其是将横切关注点与核心业务逻辑分离开。这样一来,开发者可以将日志、权限、事务等功能集中管理,而不是在每个业务方法中重复写相同的逻辑,从而减少代码重复、提高可维护性。
知道了传统Spring是什么货色后,在介绍一下Spring生态后来加入的成员。
Spring Boot
虽然大家说的是学Java就要学Spring,但实际上许多培训机构并没有基于传统的Spring(Spring Framework)讲解,而是选择更好的替代品 — Spring Boot。(跳过传统Spring的学习让我很难受,虽然能更快的上手Spring项目,但失去了对Spring的理解)
Spring Boot是Spring框架的一个子项目,旨在简化Spring应用的开发和配置过程。它主要通过“约定优于配置”的理念,减少了Spring框架在配置方面的复杂性(传统Spring配置很JB繁琐)。
Spring Boot的核心目标是在不牺牲Spring框架的灵活性和强大功能的前提下,简化Spring应用的构建。Spring Boot依赖Spring框架的功能,同时将配置和启动过程简化,因此它更适合微服务和快速开发的场景。
其他框架
其他Spring生态系统中的框架,如Spring Cloud、Spring Data、Spring Security和Spring Batch,是为了满足特定的应用场景需求而被开发出来的。Spring Framework和Spring Boot提供的是基础功能,它们的职责是简化配置(boot)、提高开发效率,提供一套基本的IoC容器和依赖注入机制,但它们没有深入覆盖到特定领域的功能。
与传统Spring的关系
Spring生态中的框架大多是基于Spring Framework的核心模块构建的,同时添加了特定领域的模块/组件来满足专业需求。因此,这些框架可以看作是将Spring核心功能与新开发的专用模块组合在一起,形成一个个完整的解决方案。具体如下:
- 利用Spring的核心模块:Spring生态中的每个框架,比如Spring Cloud、Spring Data等,都依赖Spring的IoC容器、AOP(面向切面编程)、事务管理等核心组件。这些核心组件在每个框架中都扮演基础支撑的角色,提供依赖注入、对象管理和切面支持的基础功能。
- 构建特定功能的模块:每个框架在Spring的基础之上构建了自己的独特模块来解决专门领域的需求。例如:
- Spring Cloud构建了服务发现(Eureka)、配置中心(Config)、负载均衡(Ribbon)、断路器(Hystrix)等微服务相关的组件。
- Spring Security添加了用户认证、授权、加密等安全管理组件。
- Spring Batch专门构建了批处理流程中的分块处理、任务重启、事务管理等功能。
- Spring Data提供了Repository接口和数据操作模板,用于简化数据存储和查询。
小结
总的来说,Spring是Java企业级应用的强大支柱,它的生态系统从不同层次上解决了Java开发中的各种复杂问题。未来,我们会根据项目需求,在Spring生态中选择适合的框架与模块组合,提升我们的开发效率和体验。