为什么选择 Spring 作为 Java 框架?

1. 概述

在本文中,我们将讨论 Spring 作为最流行的 Java 框架之一的主要价值体现。

最重要的是,我们将尝试理解 Spring 成为我们选择框架的原因。Spring 的详细信息及其组成部分已在我们 之前的教程中广泛介绍。因此,我们将跳过介绍性的“如何”部分,并主要关注“为什么”。

2. 为什么使用任何框架?

在我们开始任何关于 Spring 的讨论之前,首先让我们了解为什么我们首先需要使用任何框架。

像 Java 这样的通用编程语言能够支持多种应用程序。 更不用说 Java 每天都在积极地改进。

此外,还有无数开源和专有库在这方面支持 Java 。

那么,我们究竟为什么需要一个框架呢?老实说,使用框架来完成任务并不是绝对必要的。但是,出于以下几个原因,使用一个通常是明智的:

  • 帮助我们专注于核心任务,而不是与之相关的样板
  • 以设计模式的形式汇集了多年的智慧
  • 帮助我们遵守行业和监管标准
  • 降低应用程序的总体拥有成本

我们刚刚触及了表面,我们必须说,好处难以忽视。但这不可能是积极的,所以要注意的是:

  • 强制我们以特定的方式编写应用程序
  • 绑定到特定版本的语言和库
  • 添加到应用程序的资源占用

坦率地说,在软件开发和框架中没有什么银弹,Java 当然也不例外。因此,应该根据上下文来选择哪个框架或不用框架。

在本文的最后,我们将更好地做出关于 Java 中的 Spring 的决策。

3. Spring 生态系统的简要概述

在我们开始对 Spring 框架进行定性评估之前,让我们仔细看看 Spring 生态系统是什么样子的。

Spring 是在2003年的某个时候出现的,当时 Java 企业版发展迅速,开发企业应用程序很令人兴奋,但也很乏味!

Spring 最初是 Java 的 一个控制反转 (IoC)容器。我们仍然主要将 Spring 与它联系起来,事实上,它构成了框架的核心,以及在此基础上开发的其他项目。

3.1. Spring 框架

Spring 框架 被划分为多个模块,这使得在任何应用程序中都可以很容易地选择要使用的部分:

  • Core:提供核心特性,如 DI (依赖注入)、国际化、验证和 AOP (面向切面编程)
  • Data Access:支持通过JTA ( Java事务 API )、JPA (Java 持久性 API )和 JDBC (Java 数据库连接)访问数据
  • Web:同时支持 Servlet API(Spring MVC)和最近的反应式 API(Spring WebFlux),另外还支持WebSockets、STOMP 和 WebClient
  • Integration:支持通过 JMS(Java 消息服务)、JMX (Java 管理扩展)和 RMI (远程方法调用)集成到企业 Java
  • Testing:通过模拟对象、测试装置、上下文管理和缓存支持单元和集成测试

3.2. Spring 项目

但是,Spring 更有价值的是一个强大的生态系统,这个生态系统多年来一直在发展,并且还在不断发展。 它们的结构是 Spring 项目 ,它们是在 Spring 框架之上开发的。

尽管 Spring 项目的清单很长,而且一直在变化,但仍有一些值得一提的地方:

  • Boot:为我们提供了一组高度自定义但可扩展的模板,用于在几乎不花费时间的情况下创建基于 Spring 的各种项目。它使使用嵌入式 Tomcat 或类似容器创建独立的 Spring 应用程序变得非常容易。
  • Cloud:提供支持轻松地开发一些常见的分布式系统模式,如服务发现,断路器,以及 API 网关。它有助于我们减少在本地,远程甚至托管平台中部署此类样板模式的工作量。
  • Security:提供一种健壮的机制,以高度可定制的方式为基于 Spring 的项目开发身份验证和授权。通过最少的声明性支持,我们可以获得对常见攻击的保护,比如会话固定、点击劫持和跨站点请求伪造。
  • Mobile:提供检测设备并相应地调整应用程序行为的功能。此外,支持设备感知的视图管理,以获得最佳用户体验、站点首选项管理和站点切换器。
  • Batch:提供轻量级框架,用于为数据归档等企业系统开发批处理应用程序。对调度、重启、跳过、收集指标和日志记录有直观的支持。此外,还支持通过优化和分区对大容量作业进行扩展。

毋庸置疑,这是对 Spring 所提供内容的一个相当抽象的介绍。但是它为我们提供了关于 Spring 的组织和广度的足够的基础,以便我们进一步讨论。

4. Spring 操作

人们习惯于添加一个 hello world 程序来了解任何新技术。

让我们来看看 Spring 如何让编写一个不仅仅是 Hello World 的程序变得轻松自如。我们将创建一个应用程序,该应用程序将 CRUD 操作公开为一个域实体(如由内存数据库支持的雇员)的 REST API。更重要的是,我们将使用基本认证来保护我们的突变端点。最后,没有好的、旧的单元测试,任何应用程序都不能真正完成。

4.1. 项目设置

我们将使用 Spring Initializr 设置 Spring Boot 项目,这是一个方便的在线工具,可以引导具有正确依赖项的项目。我们将添加 Web、JPA、H2 和 Security 作为项目依赖项,以正确地获得 Maven 配置设置。更多细节引导在我们以前的文章之一。

4.2. 域模型和持久性

由于几乎不需要做什么,我们已经准备好定义域模型和持久性。

让我们首先将 Employee 定义为一个简单的 JPA 实体:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotNull
    private String firstName;
    @NotNull
    private String lastName;
    // Standard constructor, getters and setters
}

注意,我们在实体定义中包含了自动生成的 id 。

现在我们必须为实体定义 JPA 存储库。这就是 Spring 使它变得非常简单的地方:

public interface EmployeeRepository 
  extends CrudRepository<Employee, Long> {
    List<Employee> findAll();
}

我们所要做的就是定义一个这样的接口,Spring JPA 将为我们提供一个用默认和自定义操作充实的实现。相当整洁!在我们的其他文章中可以找到更多关于 使用 Spring Data JPA 的细节。

4.3. 控制器

现在我们必须定义一个网络控制器路由和处理我们的传入请求:

@RestController
public class EmployeeController {
    @Autowired
    private EmployeeRepository repository;
    @GetMapping("/employees")
    public List<Employee> getEmployees() {
        return repository.findAll();
    }
    // Other CRUD endpoints handlers
}

实际上,我们所要做的就是对这个类使用注解并定义路由元信息以及每个处理程序方法。

在我们的前一篇文章中详细讨论了如何使用 Spring REST 控制器。

4.4. 安全

所以现在我们已经定义了所有内容,但是如何保护创建或删除员工之类的操作呢?我们不希望对这些端点进行未经身份验证的访问!

Spring Security 在这方面非常出色:

@EnableWebSecurity
public class WebSecurityConfig 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) 
      throws Exception {
        http
          .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/employees", "/employees/**")
            .permitAll()
          .anyRequest()
            .authenticated()
          .and()
            .httpBasic();
    }
    // other necessary beans and definitions
}

这里有 更多的细节需要注意理解 ,但最重要的一点是我们只允许 GET 操作不受限制的声明式方式。

4.5. 测试

现在我们已经做了所有的事情,但是等等,我们如何测试这个呢?

让我们看看 Spring 是否可以让编写 REST 控制器的单元测试变得更容易:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class EmployeeControllerTests {
    @Autowired
    private MockMvc mvc;
    @Test
    @WithMockUser()
    public void givenNoEmployee_whenCreateEmployee_thenEmployeeCreated() throws Exception {
        mvc.perform(post("/employees").content(
            new ObjectMapper().writeValueAsString(new Employee("First", "Last"))
            .with(csrf()))
          .contentType(MediaType.APPLICATION_JSON)
          .accept(MediaType.APPLICATION_JSON))
          .andExpect(MockMvcResultMatchers.status()
            .isCreated())
          .andExpect(jsonPath("$.firstName", is("First")))
          .andExpect(jsonPath("$.lastName", is("Last")));
    }
    // other tests as necessary
}

正如我们所看到的,Spring 为我们提供了必要的基础设施来编写简单的单元和集成测试,否则这些测试将依赖于要初始化和配置的 Spring 上下文。

4.6. 运行应用程序

最后,我们如何运行这个应用程序?这是 Spring Boot 的另一个有趣的方面。尽管我们可以将其打包为常规应用程序并传统上部署在 Servlet 容器上。

但这有什么好玩的!Spring Boot 附带一个嵌入式 Tomcat 服务器

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这是一个预先创建的类,作为引导程序的一部分,具有使用嵌入式服务器启动此应用程序的所有必要细节。

此外,这是高度可定制的。

5. Spring 的替代品

虽然选择使用框架相对容易,但在框架之间进行选择通常会让我们的选择变得艰巨。但为此,我们必须至少粗略地了解 Spring 提供的功能有哪些替代方案。

如前所述,Spring 框架及其项目为企业开发人员提供了广泛的选择。如果我们对当代 Java 框架做一个快速评估,它们甚至不能与 Spring 提供给我们的生态系统相提并论。

然而,对于特定的领域,它们确实形成了一个令人信服的论据来选择替代方案:

  • Guice: 为 Java 应用程序提供一个健壮的 IoC 容器
  • Play: 非常适合作为具有响应性支持的 Web 框架
  • Hibernate: 一个基于 JPA 支持的数据访问框架

除了这些之外,还有一些新功能提供了比特定领域更广泛的支持,但仍然没有涵盖 Spring 必须提供的所有内容:

  • Micronaut: 一个基于 JVM 的框架,针对云本地微服务而定制
  • Quarkus: 一个新时代的 Java 栈,它承诺提供更快的启动时间和更小的内存占用

显然,完全迭代这个列表既不必要也不可行,但是我们在这里得到了广泛的概念。

6. 为什么选择 Spring?

最后,我们构建了所有必需的上下文来解决我们的核心问题,为什么是 Spring?我们了解框架可以帮助我们开发复杂的企业应用程序的方式。

此外,我们了解我们针对特定问题所做的选择,例如 Web,数据访问,框架方面的集成,尤其是 Java 。

现在,在所有这些当中,Spring 的亮点在哪里?让我们来探索一下。

6.1. 可用性

任何框架流行的一个关键方面是开发人员使用它是多么容易。Spring 通过多个配置选项和约定优于配置使开发人员可以轻松启动,然后准确配置他们需要的内容

Spring Boot 这样的项目使得引导一个复杂的 Spring 项目变得非常简单。更不用说,它有优秀的文档和教程来帮助任何人入门。

6.2. 模块化

Spring 受欢迎的另一个关键方面是其高度模块化的特性。我们可以选择使用整个 Spring 框架或仅使用必要的模块。此外,我们可以根据需要选择包含一个或多个 Spring 项目。

而且,我们还可以选择使用 Hibernate 或 Struts 等其他框架!

6.3. 一致性

虽然 Spring 不支持所有 Java EE 规范,但它支持所有技术,通常在必要时提高对标准规范的支持。例如,Spring 支持基于 JPA 的存储库,因此切换提供程序变得微不足道。

此外,Spring 支持行业规范,如 Spring Web Reactive 下的 Reactive Stream 和 Spring HATEOAS 下的 HATEOAS 。

6.4. 可测试性

采用任何框架在很大程度上还取决于测试构建在其上的应用程序是多么容易。Spring 的核心是倡导并支持测试驱动开发(TDD)。

Spring 应用程序主要由 POJO 组成,这自然使单元测试相对简单得多。但是,Spring 确实为 MVC 等场景提供了 Mock 对象,否则单元测试变得复杂。

6.5. 成熟

Spring 在创新、采用和标准化方面有着悠久的历史。多年来,它已经足够成熟,可以成为大型企业应用程序开发中最常见问题的默认解决方案

更令人兴奋的是积极的开发和维护。每天都在开发对新语言特性和企业集成解决方案的支持。

6.6. 社区支持

最后但并非最不重要的是,任何框架甚至类库都通过创新在行业中生存下来,而且没有比社区更好的创新场所。Spring 是由 Pivotal Software 领导的开源软件,由大型组织和个人开发者组成的支持。

这就意味着它仍然具有背景意义,而且往往具有未来主义色彩,这一点从它旗下项目的数量就可以明显看出。

7. 不使用 Spring 的原因

有各种各样的应用程序可以从不同级别的 Spring 使用中受益,并且这种应用程序的变化与 Spring 的增长速度一样快。

但是,我们必须理解 Spring 和其他框架一样,有助于管理应用程序开发的复杂性。它帮助我们避免常见的陷阱,并使应用程序随着时间的推移保持可维护性。

这是以额外的资源足迹和学习曲线为代价的,尽管可能很小。如果确实存在一个足够简单并且预计不会变得复杂的应用程序,那么根本不使用任何框架可能会带来更多益处!

8. 结论

在本文中,我们讨论了在应用程序开发中使用框架的好处。我们还进一步简要的讨论了 Spring 框架。

在讨论这个主题时,我们还研究了一些可用于 Java 的替代框架。

最后,我们讨论了促使我们选择 Spring 作为 Java 选择框架的原因。

不过,我们应该在本文的结尾给出一些建议。尽管听起来很有说服力,但在软件开发中通常没有单一的、通用的解决方案

因此,我们必须运用我们的智慧,为我们要解决的具体问题选择最简单的解决办法。

出处: spring for all 社区翻译组

原文发布于微信公众号 - 乱敲代码(gh_baf1250e9b02)

原文发表时间:2019-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券