什么是 Spring?为什么学它?
前言
欢迎来到本篇文章!在这里,我将带领大家快速学习 Spring 的基本概念,并解答两个关键问题:什么是 Spring,以及为什么学习 Spring。
废话少说,下面,我们开始吧!
Spring 官方文档:https://docs.spring.io/spring-framework/docs/5.2.24.RELEASE/spring-framework-reference/
为什么需要学习 Spring?
- 简化我们的企业级应用程序的开发,提升我们的开发效率。
- 学 Java 的路上不得不学 Spring,不学直接用 Spring Boot 是可以,开箱即用,但是很难学懂,可能只是会用,不能知其然而知其所以然。
- 面试会问的啊!工作会用的啊!所以需要学嘛!OK!
Spring 这个词,指的是什么?
Spring
这个术语在不同的上下文中有不同的含义。它可以用来指代 Spring Framework
项目本身,这是梦开始的地方。
后来随着时间的推移,其他基于 Spring Framework
构建的项目也相继出现。当人们说 Spring
时,通常指整个项目家族。不过,在本系列中,我们就只指代它本身,即 Spring Framework
本身。
Spring Framework
被分为多个模块,应用程序可以选择需要哪些模块。核心容器模块包括配置模型和依赖注入机制等内容。除此之外,Spring Framework
还为不同类型应用架构提供了基础支持,包括消息传递、事务数据和持久化以及 Web 开发等领域,并且同时提供了基于 Servlet
的 Spring MVC Web
框架和并行运行的 Spring WebFlux
响应式 Web 框架。
Spring 的模块
实际上,Spring Framework
大约由 20 个模块组成。这些模块分为核心容器、数据访问/集成、Web、AOP(面向切面编程)、仪表板、消息和测试等。如官网上给出的这张图所示:
Core Container(核心模块)
当我们谈论 Spring 的核心容器时,我们指的是一些模块,它们共同构成了这个框架的基础。这些模块包括 spring-core
、spring-beans
、spring-context
、spring-context-support
和 spring-expression
。
首先,让我们来了解一下 spring-core
和 spring-beans
模块。它们提供了一些基本功能,其中最重要的是「IoC(控制反转)」和「依赖注入」。简单来说,IoC 允许我们将对象的创建和管理交给框架来处理,而不是我们自己手动创建和管理。依赖注入则是一种将对象之间的依赖关系注入到它们之间的过程,这样可以实现对象之间的解耦。
另外,BeanFactory
是一个工厂模式的复杂实现,它的作用是消除编写单例模式的需要,并且允许我们将对象的配置和规范与实际的程序逻辑分离开来。
接下来是 Context
(spring-context
)模块,它是在 Core
和 Beans
模块的基础上构建的。Context
模块提供了一种类似于 JNDI(Java命名和目录接口)注册表的方式来访问对象。除了继承 Beans
模块的功能外,Context
模块还添加了对国际化、事件传播、资源加载等功能的支持。它还能够通过 Servlet 容器等方式透明地创建上下文。此外,Context
模块还支持一些 Java EE 特性,如 EJB(企业级 Java Bean)、JMX(Java管理扩展)和基本的远程处理。在 Context
模块中,ApplicationContext
接口是重点关注的对象。另外,spring-context-support
模块为将常见的第三方库集成到 Spring 应用程序上下文中提供了支持,尤其是在缓存(EhCache、JCache)和调度(CommonJ、Quartz)方面。
最后, spring-expression
模块,它提供了一个强大而灵活的表达式语言,用于在运行时查询和操作对象图(object graph)。该语言是 JSP 2.1 规范中统一表达式语言(unified EL)的扩展。它支持设置和获取属性值、属性赋值、方法调用、访问数组、集合和索引器的内容,以及逻辑和算术运算符、命名变量等。通过 Spring IoC
容器,我们还可以按名称检索对象。此外,该表达式语言还支持列表投影、选择和常见的列表聚合操作。
AOP 和 Instrumentation
spring-aop
模块是 Spring 框架中用于实现面向切面编程的一部分,它遵循 AOP Alliance 标准。
那么什么是面向切面编程呢?简单来说,它允许我们在代码中定义方法的拦截器和切入点,从而将某些功能与实际业务逻辑分离开来,以实现更清晰的代码结构和更好的模块化。举个例子,比如当我们需要在代码中引入一些日志记录、安全性检查、性能监控的代码,那么这些代码就是横切关注点,我们可以使用 AOP 来实现这些代码的引入,而不是将这些代码分散到各个业务逻辑中。通过使用 AOP,我们可以将这些通用的横切关注点定义为切面,并将它们应用到适当的方法上,从而实现代码的解耦和重用。
此外,Spring 还提供了单独的 spring-aspects
模块,用于与 AspectJ 进行集成。AspectJ 是一个功能强大的 AOP 框架,通过与 Spring 的集成,我们可以利用 AspectJ 的更高级功能来实现更复杂的切面编程。
另外还有一个模块叫做 spring-instrument
,它提供了类仪表化(instrumentation)的支持和类加载器实现,在某些应用服务器中可以使用。这个模块的作用是提供一些工具和机制,以便在运行时对类进行修改和增强,从而实现一些特定的需求。例如,spring-instrument-tomcat
模块是针对 Tomcat 服务器的特定实现,它提供了用于仪表化的代理机制。
Messaging
Spring 4 引入了一个名为 spring-messaging
的模块,它包含了 Spring Integration 项目的核心抽象,例如 Message
、MessageChannel
、MessageHandler
等等。这个模块的目的是提供消息传递应用程序的基础支持。
通过 spring-messaging
模块,我们可以构建基于消息传递的应用程序,其中不同组件之间通过消息进行通信。以下是一些关键概念和功能:
Message
:消息是应用程序中传递的数据单元。它可以包含有关消息内容和元数据的信息。MessageChannel
:消息通道是消息在应用程序中传递的路径。它充当发送者和接收者之间的中介。MessageHandler
:消息处理器是负责接收和处理消息的组件。它可以执行特定的业务逻辑或转发消息给其他组件。
spring-messaging
模块还引入了一组注解,用于将消息映射到方法,类似于 Spring MVC 中基于注解的编程模型。这使得我们可以通过简单的注解来定义消息的处理方式,让代码更加清晰和易于理解。
Data Access/Integration
当我们处理数据时,Spring 的数据访问/集成层提供了一些模块,以帮助我们更轻松地与数据库和其他数据源进行交互。
spring-jdbc
模块简化了与数据库进行交互的过程。它提供了一个抽象层,让我们可以使用更简单、更易于理解的代码来执行数据库操作,而不必处理繁琐的细节。spring-tx
模块支持事务管理。事务是用来确保数据的一致性和完整性的机制。使用 Spring 的事务管理模块,我们可以以编程式或声明式的方式来管理事务,从而更轻松地处理数据的变化和操作。spring-orm
模块提供了与对象关系映射(ORM)框架的集成。ORM 是一种将数据库中的数据映射到对象的技术,它使得我们可以使用面向对象的方式来操作数据库。通过使用 Spring 的 ORM 模块,我们可以方便地集成流行的 ORM 框架(如 Hibernate、MyBaits),并结合 Spring 的其他功能,例如简单的声明式事务管理。spring-oxm
模块提供了对象和 XML 之间的映射支持。它可以帮助我们将 Java 对象转换成 XML 格式,或者将 XML 转换回 Java 对象。这对于处理与 XML 相关的数据非常有用。spring-jms
模块用于处理 Java 消息服务(Java Message Service)。它提供了生成和消费消息的功能。从 Spring Framework 4.1 版本开始,它还与spring-messaging
模块进行了集成,使得基于消息传递的应用程序开发更加方便。
Web
Web 层由 spring-web
、spring-webmvc
等模块组成。
spring-web
模块提供了基本的 Web 功能。它包含处理 MultipartFile 上传、使用 Servlet 监听器进行初始化 IoC 容器的功能。该模块还包含与Web相关的部分,如 HTTP 客户端和 Spring 远程支持,以便与其他Web服务进行通信。spring-webmvc
模块(也称为Web-Servlet模块)是 Spring 框架中用于构建 Web 应用程序的重要模块。它实现了 Model-View-Controller(MVC)架构和 RESTful Web 服务。使用 Spring MVC,我们可以将业务逻辑代码和 Web 表单清晰地分离,实现更好的代码组织和可维护性。该模块与 Spring 的其他功能无缝集成,使我们能够轻松地使用依赖注入、事务管理等功能来构建灵活和可扩展的Web应用程序。
Test
spring-test
模块支持使用 JUnit 或 TestNG 对 Spring 组件进行单元测试和集成测试,它提供了一致的 Spring ApplicationContext
加载和缓存机制,并提供了 Mock
对象,便于我们进行测试。
Spring 的历史
Spring 框架于 2003 年诞生,是对早期 J2EE 规范复杂性的回应。虽然有些人认为 Java EE 和 Spring 存在竞争关系,但实际上,Spring 与 Java EE 相辅相成。Spring 编程模型并不包含 Java EE 平台规范;相反,它集成了来自 EE 大伞下精心挑选的个别规范:
-
Servlet API(JSR 340)
-
WebSocket API(JSR 356)
-
Concurrency Utilities(JSR 236)
-
JSON Binding API(JSR 367)
-
Bean Validation(JSR 303)
-
JPA(JSR 338)
-
JMS (JSR914),以及必要时用于事务协调的 JTA/JCA 设置。
Spring 框架还支持依赖注入(JSR330)和常见注解(JSR250)规范,我们开发人员可以选择使用这些规范而非由 Spring 框架提供的特定机制。
从 Spring Framework 5.0 开始,Spring 要求 Java EE 7 级别(例如 Servlet 3.1+,JPA 2.1+)作为最低要求,同时在运行时提供与 Java EE 8 级别的新API(例如 Servlet 4.0、JSON Binding API)的开箱即用集成。这使得 Spring 完全兼容 Tomcat 8 和 9、WebSphere 9 以及 JBoss EAP 7 等服务器。
随着时间推移,在应用程序开发中 Java EE 的角色也在不断演变。在 Java EE 和 Spring 的早期,应用程序是为部署到应用服务器而创建的。如今,在 Spring Boot 的帮助下,应用程序以 devops 和云友好的方式创建,Servlet 容器被嵌入其中并且易于更改。从 Spring Framework5 开始,WebFlux 应用程序甚至不直接使用 Servlet API,并且可以运行在非 Servlet 容器(例如 Netty )上。
Spring 继续创新和发展。除了 Spring Framework 之外,还有其他项目,例如 Spring Boot、Spring Security、Spring Data、Spring Cloud、Spring Batch 等等。
Spring 设计理念
当你学习一个框架时,了解它所做的事情以及遵循的原则同样重要。以下是 Spring Framework 的指导原则:
-
在每个层面提供选择:Spring 允许我们尽可能地推迟设计决策。例如,我们可以通过配置切换应用程序所连接的数据库而无需更改代码。对于许多其他基础设施问题和第三方API的集成也是如此。
-
容纳不同的观点:Spring 非常灵活,没有固定的方式来解决应用程序的需求。它提供了多种方法来完成相同的任务,以适应不同开发者的不同观点和需求。
-
保持强大的向后兼容性:Spring Framework 的设计经过精心考虑,尽量减少对你已有代码的影响。这意味着当我们升级到新的版本时,我们的应用程序仍然可以正常运行,而无需担心因为框架更新而导致问题。Spring 还支持多个 Java 开发工具包(JDK)版本和第三方库,这样你可以继续使用 Spring 来开发和维护你的应用程序。
-
关注 API 设计:Spring 团队花费了大量的时间和精力来设计直观易懂、稳定可靠的 API。他们努力确保 API 在多个版本和多年的时间跨度中保持一致性,这样我们就可以更轻松地理解和使用它们。
-
确立高标准代码质量:Spring Framework 强调清晰、准确的文档注释。它是少数几个代码结构清晰且包之间没有循环依赖关系的项目之一。这种高标准的代码质量有助于提高框架的可维护性和可扩展性。
所以什么是 Spring?
Spring 是一个轻量级的、开源的 Java 框架,实现了 IoC(Inversion of Control)和 AOP(Aspect Oriented Programming)等功能。
在 Spring 的官网介绍中,Spring 被描述为「构建企业级应用程序的一站式框架」,它提供了如下的优点:
- 便于开发:Spring 的组件化和松耦合的特性使得开发变得更加简单,开发者可以更加专注于业务逻辑的实现。
- 便于测试:Spring 的代码结构和依赖注入机制使得测试变得更加容易。
- 便于集成:Spring 的可插拔的架构,使得其可以方便地与其他框架和组件进行集成。
- 便于部署:Spring 应用程序的部署非常简单,开发者只需要将应用程序打成 war 包,然后将其部署到支持 Java 应用程序的服务器上即可。
Spring 框架包含了如下的模块:
- 核心容器(Core Container):包括 IoC 和 DI(Dependency Injection,依赖注入)、事件、资源、国际化、验证、数据绑定、类型转换、SpEL 和 AOP 等核心功能。
- AOP:支持面向切面编程。
- 工具(Instrumentation):提供了一系列的工具和支持,如 JMS、JCA、JMX、电子邮件、任务调度和缓存等。
- 数据访问/集成(Data Access/Integration):包括对 JDBC、ORM 框架(如 Hibernate、MyBatis)事务处理,DAO 等的支持。
- Web:包括对 Web 应用程序开发的支持,如 Spring MVC 和 Spring WebFlux 网络框架等。
- 测试(Test):包括对 JUnit、TestNG 等的支持。
没有 Spring 和有 Spring 的区别
那到底是怎样简化了呢?体现在哪里呢?下面,为了直观展示 Spring 是如何简化我们开发的过程的,将写一个代码示例,让大家看看是怎样的区别。
对象管理
当没有 Spring 时,Java EE 开发的主要方式是使用 JSP、Servlet 和 EJB 等技术。你想一想,刚开始学习 JSP 的时候,是不是这样,没有任何框架,纯纯自己操作所有东西。
对于系统中多个对象之间的关系,没有 Spring 的时候,我们需要手动创建和管理对象之间的依赖关系。
这句话可能初学者不是很好理解,我举个例子。
这里有两个设计好的系统中的两个类,Employee 和 Department(用于描述员工以及部门信息的类)。
Employee.java:
public class Employee {
private int id;
private String name;
private Department department;
// 省略 getter 和 setter
}
Department.java:
public class Department {
private int id;
private String name;
// 省略 getter 和 setter
}
未使用 Spring 的时候
我们现在的业务假设是需要打印员工的部门信息,那么我们就需要手动管理它们之间的依赖关系的,代码如下:
public class Main {
public static void main(String[] args) {
Department department = new Department(1, "Just do IT");
Employee employee = new Employee(1, "god23bin", department);
System.out.println(employee.getDepartment().getName());
}
}
你创建一个 Employee 对象,就必须自己再去创建一个 Department 对象(因为 Employee 对象依赖于 Department 对象),并将 Department 对象给关联到 Employee 对象上。是吧。现在,我相信屏幕前的你已经懂了所谓的手动创建和管理对象之间的依赖关系了。
使用 Spring 的时候
当你使用 Spring 的时候,就完全不需要这么做。依然是这个例子,现在我使用 Spring 来操作,对象的管理就交给 Spring 处理,来看看我怎么写的:
@Configuration
public class AppConfig {
@Bean
public Department department() {
return new Department(1, "Just do IT");
}
@Bean
public Employee employee() {
return new Employee(1, "god23bin", department());
}
}
我写了一个 AppConfig
类,在类上使用了一个 @Configuration
注解,表示这是一个配置类。
接着,写了两个方法,分别返回了一个员工对象和一个部门对象,而且在方法上使用了一个 @Bean
注解,表示这个方法返回的对象是交给 Spring IoC 进行管理的。
这两个对象都是通过调用构造方法来创建的,其中 Department 对象则被注入到了 Employee 对象中。(注入,你就理解成 setXxx 方法)
在最上面进行介绍的时候,有一个概念,就是「容器」,这个容器人们也习惯称「Ioc 容器」,实际上就是 Spring 用来存放与管理应用程序中所有交给它的对象的。
现在在这个容器中,就有 Department 对象和 Employee 对象。
我们的业务依旧是打印员工的部门信息,此刻,我们只需要从「容器」中获取我们需要的对象就可以了,直接获取员工对象,不用手动自己 new
一个员工对象,也不需要自己 new
一个部门对象了。
我们通过 AnnotationConfigApplicationContext
来加载配置类 AppConfig
,然后通过 getBean 方法来获取 Employee 对象,此过程 Spring 完成了依赖注入的效果,Employee 对象是具有 Department 对象的。
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Employee employee = context.getBean(Employee.class);
System.out.println(employee.getDepartment().getName());
}
}
不过,实际上,我们在真正的项目中,并不会这样去使用,即不会去手动写 context.getBean()
等这些代码,而是直接通过依赖注入的方式,这个后面再写咯。现在知道是怎么回事就 OK 啦!
当然,由于篇幅有限,可能目前你还没能理解这样做有什么好处,可能会有各种疑惑,没关系,慢慢学习下去就会迎刃而解了。
其他的管理
在没有 Spring 时,我们需要在代码中手动处理一些与业务逻辑无关的问题,比如连接池和事务管理等。而有了 Spring 之后,这些问题都可以通过 Spring 的 API 和组件来解决,从而使代码更加简洁易读。
总结
Spring 是一个很牛的、开源的 Java 框架,实现了 IoC(Inversion of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)等功能。
Spring 的核心特点包括便于开发、便于测试、便于集成和便于部署,啥都方便。
Spring 框架的出现简化了 Java EE(Enterprise Edition)开发的过程。在没有使用 Spring 的情况下,开发 Java EE 应用程序需要手动创建和管理对象之间的依赖关系,而使用 Spring 可以通过配置和注解来实现对象的自动管理和依赖注入。Spring 还提供了许多其他模块和功能,如数据访问/集成、Web 开发支持、AOP、工具等,使开发人员可以更加便捷地开发企业级应用程序。
总之,学习 Spring 可以帮助我们更好地理解和应用现代企业级 Java 开发的基本概念和最佳实践,提高开发效率和代码质量。
参考
最后的最后
希望各位屏幕前的靓仔靓女们
给个三连!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!
咱们下期再见!