当我们谈论Spring的时候到底在谈什么

你好,这里是codetrend专栏“Spring6全攻略”。欢迎点击关注查看往期文章。

Spring对于不做程序开发的人来说字面意思就是春天,四季的开始。

对于程序员来说这个单词完全拥有另外一个含义,Spring指的是一个开源项目,而这个项目非常厉害。

Spring这个术语在不同的语境中有不同的含义。它可以用来指代Spring Framework项目本身。随着时间的推移,其他Spring项目也建立在Spring Framework之上。当人们说“Spring”时,通常指的是整个项目家族。

Spring Framework被分为多个模块。应用程序可以选择它们需要的模块。在核心部分是核心容器的模块,包括配置模型和依赖注入机制。

除此之外,Spring Framework为不同的应用架构提供了基础支持,包括消息传递、事务性数据和持久性,以及Web。它还包括基于Servlet的Spring MVC Web框架,同时也有Spring WebFlux响应式Web框架。

Spring的来龙去脉可以通过这个Mermaid流程图表示。

graph LR Jakarta/Java_EE --实现--> Spring_Framework Spring项目 --使用--> Spring_Framework

Spring与企业应用开发

Java EE(Java Platform, Enterprise Edition)是一种基于Java编程语言的企业级应用程序开发平台。它提供了一套全面的API和运行时环境,用于简化企业级应用程序的开发和部署。Java EE包括各种技术规范和API,如Servlets、JSP、EJB、JPA、JMS等,旨在帮助开发者构建可靠、安全、可扩展的企业级应用程序。

Java EE 也是是一个不断发展的解决方案,它设计的接口和框架以及整个解决方案在Spring框架中都有体现。也就是说Spring是Java EE的继承者和发扬者。

Spring使得创建Java企业应用程序变得简单。它提供了一切您在企业环境中需要的内容,支持Groovy和Kotlin作为JVM上的替代语言,并灵活地根据应用程序的需求创建多种架构。从Spring Framework 6.0开始,Spring要求使用Java 17或更高版本。

Spring支持广泛的应用场景,而这些解决方案就是为企业开发而生。在大型企业中,应用程序通常存在很长时间,必须在开发人员无法控制的JDK和应用服务器上运行。其他应用可能作为一个包含嵌入式服务器的单个jar文件运行,可能在云环境中。还有一些可能是独立的应用程序(如batch 或者 integration workloads),不需要服务器。

Spring是开源的。这也是Spring成功的秘诀之一。它拥有庞大而活跃的社区,基于各种真实用例提供持续反馈。Spring通过不断迭代、不断不断发展变得强大。

Spring的历史

Spring 框架诞生于 2003 年,是为了应对早期 J2EE 规范的复杂性而开发的。

尽管有人认为 Java EE 及其现代继承者 Jakarta EE 与 Spring 处于竞争关系,但实际上它们是互补的。

Java Specification Requests (JSRs) 是 Java Community Process (JCP) 下制定的技术规范提案,它代表了一种标准化的过程。每个 JSR 都是为了定义或更新 Java 平台的一部分,涵盖了从核心语言、API 到企业级平台的各种技术规格。比如 Servlet API(JSR 340)、WebSocket API(JSR 356)、JPA(JSR 338) 等都是 JSR 规范的具体实例,它们定义了 Java 开发人员应该遵循的标准接口和实现。

Spring框架实现了 JSR 规范。通过JSR规范既可以保持框架的一定兼容性,又能保证框架的推广和保持流行。但实现规范是一个选择性的过程,Spring6框架的轻量级设计思想决定了实现规范的选择性。

Jakarta EE(前身为 Java EE)是一个企业级 Java 平台标准,它整合了一系列经过 JCP 认证的 JSR 规范,为开发企业级应用提供一整套解决方案,包括但不限于 web 层、业务层、持久化层和消息传递等方面。Spring Framework 支持并集成了许多 Jakarta EE 中的关键技术规范,同时又提供了自己特有的编程模型和扩展功能。

Spring 编程模型并不包含 Jakarta EE 平台,而是从传统 Java EE 范围内精心选择的个别规范集成,包括:

  • Servlet API(JSR 340)
  • WebSocket API(JSR 356)
  • 并发工具(JSR 236)
  • JSON 绑定 API(JSR 367)
  • Bean 验证(JSR 303)
  • JPA(JSR 338)
  • JMS(JSR 914)
  • 用于事务协调的 JTA/JCA 设置

Spring 框架还支持依赖注入(JSR 330)和通用注解(JSR 250)规范,应用开发人员可以选择使用而不是 Spring 框架提供的特定机制。这也是程序员通常提到的基于注解开发的来源。因为实现了这些统一规范,Spring的兼容和功能都很强大。

最初这些JavaEE规范的实现都是放在 javax 包,也就是Spring Framework 5 以前的框架都是放在这个包路径。比如javax.servlet.http.HttpServletRequest就是实现的这个规范Servlet API(JSR 340)的一个类。

而在Spring Framework 6中,这个类的路径变成了Jakarta.servlet.http.HttpServletRequest。这更能说明Spring与Java EE的关系。

在现在的Springy应用中,Java/Jakarta EE 在应用程序开发中的角色已经发生了变化。在 J2EE 和 Spring 早期,应用程序被创建为部署到应用服务器上。

现在借助 Spring Boot,应用程序以 devops 和云友好的方式创建,内嵌了 Servlet 容器,易于更改。

截至 Spring Framework 5,WebFlux 应用程序可以不直接使用 Servlet API,可以在不是 Servlet 容器的服务器上运行(例如 Netty)。

Spring 是在不断创新和发展。需要集成对应的内容,只需要引入依赖修改版本即可。

Spring与Spring生态项目有版本的限制,比如Spring5对应Springboot2,而最新的Spring6则对应最新的Spring Boot 3。

以下通过使用jarkata的实现Bean 验证(JSR 303)这个规范的代码例子来说明Spring Framework是如何实现Bean 验证(JSR 303)的。

package io.yulin.learn.spring.s101;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.constraints.*;
import lombok.Data;

import java.util.Set;

/**
 * 演示使用jakarta ee 中的api
 * @author nine
 * @since 1.0
 */
public class JakartaEE {

    public static void main(String[] args) {
        System.out.println("hello jakarta ee");
        UserReq userReq = new UserReq();
        userReq.setName("John Doe");
        userReq.setAge(180);
//        userReq.setEmail("[email protected]");
        userReq.setSex("Male");

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<UserReq>> violations = validator.validate(userReq);

        if (violations.isEmpty()) {
            System.out.println("UserReq is valid");
        } else {
            for (ConstraintViolation<UserReq> violation : violations) {
                System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
            }
        }
    }

}

@Data
class UserReq{
    @NotBlank
    private String name;
    @Max(value = 170, message = "年龄不能大于170岁")
    @Min(value = 1,message = "年龄不能小于1岁")
    private Integer age;
    @Email(message = "请输入邮箱格式")
    @NotEmpty
    private String email;
    @NotBlank
    private String sex;
}

通过输出可以发现,通过简单的注解+jarkata工具就可以验证输入的正确性。减少了非常多的ifelse的判断,大大降低了代码的复杂度。

email 不能为空
age 年龄不能大于170岁

对业务pojo的验证接口是这样的。实现整个验证过程的一个实现是org.hibernate.validator.internal.engine.ValidatorImpl#validateInContext。通过反射、解析注解等过程验证业务类。

	/**
	 * 对对象上的所有约束进行验证。
	 */
	<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);

Java Specification Requests、Jakarta EE、Spring6 的关系

总的来说Spring是一个集大成者,既选择了部分Java Specification Requests,也选择了Jakarta EE。

  • JSRs 与 Jakarta EE 直接相关,因为 Jakarta EE 是由一系列 JSRs 组成的,它是按照 JSR 规范实现的企业级平台标准。
  • Spring Framework 与两者都有关联,因为它既支持和遵守了部分 Jakarta EE 中基于 JSR 的规范,又在此基础上发展了自己的技术和架构,提供了一套不完全依赖于 Jakarta EE 的完整应用框架。

它们三者的区别在于:

  • JSRs 是规范和标准层面的东西,它定义了技术接口和行为,而不提供具体的实现。
  • Jakarta EE 是一套遵循 JSRs 的企业级平台实现,提供了完整的软件栈和部署环境。
  • Spring Framework 则是一个独立于 Jakarta EE 规范之外的应用框架,虽然兼容并集成了许多 Jakarta EE 技术,但它的目标是在简化企业级应用开发的同时,提供更多自由度和灵活性。

三者之间的关系可以mermaid流程图表示:

flowchart LR JSR --实现--> Jakarta_EE JSR --实现--> Spring Jakarta_EE --开箱即用的--> Spring

Spring的设计原则

当学习一个框架时,重要的不仅是了解它能做什么,还有它遵循的原则。

以下是Spring Framework的指导原则(来自Spring Framework 的文档):

  • 在每个层面提供选择。Spring允许您尽可能推迟设计决策。例如,您可以通过配置在不更改代码的情况下切换持久性提供程序。对于许多其他基础设施问题和与第三方API集成也是如此。
  • 容纳多元化观点。Spring支持灵活性,不对应该如何完成事务持有固定看法。它支持各种不同观点的应用需求。
  • 保持强大的向后兼容性。Spring的演进经过精心管理,版本之间几乎没有重大变化。Spring支持一系列精心选择的JDK版本和第三方库,以便维护依赖于Spring的应用程序和库。
  • 关注API设计。Spring团队花费大量时间和精力制定直观且经得起时间考验的API。
  • 设定高标准的代码质量。Spring Framework非常重视有意义、当前且准确的javadoc。它是为数不多的几个项目之一,可以声称具有清晰的代码结构,在各个包之间没有循环依赖。

其中第一条原则很显然就是开发者常常提到的“默认大于配置”。这条原则贯穿了Spring框架的全生命周期。

通过上述原则可以看到Spring之所以如此流行和强大,并不仅仅是因为开源。还因为它优秀的设计与实现。

与程序员的业务开发流程相对比,这也是一个很好的开发流程学习模板。通过良好的设计指导更加完美的实现,通过review闭环输出高质量的代码。

工程化的设计在开发者的代码和Spring6框架无处不在。通过对Spring的学习可以提升工程化开发的认知和技能。

关于作者

来自一线全栈程序员nine的八年探索与实践,持续迭代中。欢迎关注公众号“雨林寻北”或添加个人卫星codetrend(备注技术)。

热门相关:赠我深爱如长风   我写的书实在太毒了   剑斗九天   剑道邪尊Ⅱ   拳皇之梦