Skip to main content

《Spring in Action 6th edition》第一章:Spring 起步

8 min read

唯一不变的就是变化 - 希腊哲学家拉克利特(heraclitus)

Spring框架在不断的变化,以解决现代应用开发中的问题,微服务,反应式编程,Spring Boot等等。

1.1什么是Spring

任何实际的应用程序都是由很多组件组成的,每个组件负责整个应用功能的一部分,这些组件需要与其他的应用元素进行协调以完成自己的任务。当程序运行时,需要以某种方式创建并引入这些组件。

Spring的核心是提供了一个容器(Container),通常称为Spring应用上下文(Spring application context),会创建和管理应用组件--bean, 会在Spring应用上下文中装配在一起,从而形成一个完整的应用程序。

将bean装配在一起的行为是通过一种基于依赖注入(Dependency Injection, DI)的模式实现的。此时,组件不会再去创建他所依赖的组件并管理他们的生命周期,使用依赖注入的应用依赖于单独的实体(容器)来创建和维护所有的组件,并将其注入到需要他们的bean中。通常,这是通过构造器参数和属性访问方法来实现的。

以前Spring通过一个或多个XML文件来进行依赖的定义,现在一般通过基于注解的方式。

1.2 初始化Spring应用

这里我认为无论通过那种方式,只要达到目的即可,没必要学习太多创建项目的方式。

所以,不同于书中介绍,我们使用Intellij Idea来创建

1.2.1 初始化项目

1763297780017

创建好之后,等待依赖下载完毕

1.2.2 Spring项目目录结构

1763297836102

  • maven相关
    • graddle和maven使用的都比较多,这里为了和书里面保持一致,用maven
    • mvnw和mvnw.cmd: 是Maven包装器脚本(wrapper)
    • pom.xml:maven构建规范
  • Spring SpringBoot
    • TacoCloudApplication.java SpringBoot的主类
  • resources
    • static: 存放静态内容
    • templates: 渲染内容到浏览器的模板文件,我们选用的Thymeleaf就是一个模板的库
    • application.properties 配置属性的地方
  • 测试
    • TacoCloudApplicationTests.java 简单的测试类

探索构建规范

<packaging>, 这里将应用构建成了一个可执行的jar文件,而不是war文件,因为所有的Java云平台都能够运行可执行的JAR文件,所以Spring Initializr基于云思维,默认都是使用JAR打包方式,当然你可以修改。

<parent>,<version>表名项目以 spring-boot-starter-parent作为其父POM,这个父POM为Spring项目常用的一些库提供了依赖管理。

<dependencies>元素下面声明了四个依赖,这些大都是我们之前创建项目的时候选择的

也可以看到好几个是starter依赖(Spring Boot Starter依赖本身不包含库代码,传递性的拉取其他库),其好处:

  1. 构建文件会显著减小并且易于管理,这样不必为每个所需的库都声明依赖
  2. 能够根据所提供的功能来思考依赖,而不是根据库的名称。
  3. 不必担心版本的问题

最后 pom.xml里面还有一个Spring Boot插件:

  • 提供了一个maven goal,允许我们使用Maven来运行应用
  • 确保依赖的所有库都会包含在可执行文件中,并且能够保证它们在运行时类路径下是可用的
  • 在jar中生成一个manifest文件,将引导类声明为可执行的JAR主类

引导应用

我们通过可执行的JAR文件的形式来运行应用,所以需要有一个主类,它将会在JAR运行的时候被执行。同时还需要一个最小化的Spring配置,以引导该应用。这就是TacoCloudApplication所做的事儿。

TacoCloudApplication的 @SpringBootApplication是一个组合注解:

  • @SpringBootConfiguration
    • 将类声明为配置类,其实就是 @Configuration的特殊形式
  • @EnableAutoConfiguration:启用Spring Boot的自动配置
  • @ComponentScan:启用组件扫描

TacoCloudApplication的main方法,是JAR文件执行的时候要运行的方法,这里会调用 SpringApplication 的静态run方法,后者会真正执行引用的引导过程,创建Spring应用上下文,传递的参数:

  • 一个是配置类(传递给run的配置类不一定要和引导类相同,但这是最便利,最典型的做法)
  • 一个是命令行参数

测试应用

这个测试类会执行必要的检查,确保Spring应用上下文能够成功加载

1.3 编写Spring应用

目标:

  • 添加一个控制器类,处理主页相关的请求
  • 添加一个视图模板,用来定义主页看起来是什么样子

1.3.1 处理web请求

Spring自带了一个强大的web框架,SpringMVC。

SpringMVC的核心是控制器概念,控制器是处理请求并以某种方式进行信息相应的类。在面向浏览器的应用中,控制器会填充可选的数据模型并将请求传递给一个视图,以便于生成返回给浏览器中的HTML。

下面是一个简单的控制器,用来处理对根路径("/")的请求,并将这些请求转发到主页视图。

package com.chengxuyuancd.tacocloud.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "home";
}
}

  • @Controller其实并没有做太多的事儿,主要目的是为了让 @ComponentScan将这个类识别为一个组件。所以这里Spring会自动发现它,并创建一个 HomeController的实例作为Spring应用上下文中的bean。
  • 而实际上,@Service, @Component, @Repository都可以做到和 @Controller一样的效果
  • home()是一个简单的控制器方法,带有 @GetMapping注解,如果针对"/" 发送HTTP GET请求,则这个方法将会处理请求,返回String类型的home值。
  • home()方法返回的值将会被解析成视图的逻辑名,视图可以有多种实现方式,这里将会使用Thymeleaf模板
  • 模板的名称由逻辑视图名派生而来,加上"/templates/"前缀和".html"后缀,最终形成的模板路径将是:"/templates/home.html"

1.3.2 定义视图

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Taco CLoud</title>
</head>
<body>
<h1>Welcome to...</h1>
<img th:src="@{/images/TacoCloud.png}">
</body>
</html>

这里使用了Thymeleaf的th:src属性和 @{...}表达式,用来引用相对于上下文路径的图片作为img的参数。

Spring中静态资源的地址默认是: /src/main/resources/static

1.3.3 测试控制器

一般的测试,对HTML页面进行断言比较困难,但Spring测试提供了一些支持。

我们期望测试对根路径("/")发送一个HTTP GET请求并期望得到成功的结果,结果应该包含"Welcome to..."

package com.chengxuyuancd.tacocloud;

import com.chengxuyuancd.tacocloud.controller.HomeController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(HomeController.class)
class TacoCloudApplicationTests {

@Autowired
private MockMvc mockMvc;

@Test
void contextLoads() {
}

@Test
void testHomePage() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("home"))
.andExpect(content().string(containsString("Welcome to...")));
}
}

这里我们没有使用 @SpringBootTest 注解,而是使用 @WebMvcTest,他会让测试在Spring MVC应用的上下文中执行,具体的是,这里会将HomeController注册到Spring MVC中,这样就可以向他发送请求了。

@WebMvcTest也会为测试Spring MVC应用提供Spring环境支持,仿造了Spring MVC的运行机制,测试类被注入了一个MockMvc,能够让测试实现mockup。

测试testHomePage()方法中,首先使用MockMvc对象对"/"根路径发送HTTP GET请求,设置的预期如下:

  • 相应应该返回HTTP 200(OK)状态码
  • 视图的逻辑名称应该是home
  • 渲染后的视图应该包含文本"Welcome to..."

1.3.4 构建和运行测试

这里我提供两种我常用的方式:

  1. 直接运行 TacoCloudApplication.java文件
  2. 使用maven运行: ./mvnw spring-boot:run

控制台会打印出来Spring的ASCII字符,以及Tomcat已经在8080端口启动的日志

1763386158951

1.3.5 Spring Boot DevTools

DevTools为开发人员提供了很多便利:

  1. 代码变更后应用会自动重启
  2. 面相浏览器的资源(如模板,JavaScript,样式表)等发生变化的时候,自动刷新浏览器
  3. 自动禁用模板缓存
  4. 如果使用H2数据库,内置了H2的控制台

1.3.6 回顾一下

我们执行了如下步骤:

  • 使用Spring Initializr创建初始的项目结构
  • 编写控制器类处理针对主页的请求
  • 定义一个视图模板来渲染主页
  • 编写一个简单的测试类来验证工作符合预期

1.4 Spring 概览

1.4.1 Spring核心框架

Spring的核心中有一个是Spring MVC

数据持久化的基础操作

最新版的Spring中,添加了反应式(reactive)风格编程的支持,包括Spring WebFlux

1.4.2 Spring Boot

1.4.3 Spring Data

关系型数据库(JPA),文档数据库(Mongo),图数据库(Neo4j)

1.4.4 Spring Security

1.4.5 Spring Integration 和 Spring Batch

1.4.6 Spring Cloud

Loading Comments...