Spring实战(第5版)

克雷格·沃斯

译者序

  • 从XML配置、注解配置,再到Spring Boot的自动化配置,Spring在不断简化,开发人员需要做的额外工作越来越少。
  • 因为这些东西都是不稳定的、易变的,想要在新知识层出不穷的领域中不被淘汰,我们更应该去追求一些内在稳定不变的知识,比如技术规范、设计原理等。

前言

  • Spring 5的主要功能是对反应式编程的支持,包括Spring WebFlux

第1章 Spring起步

  • 另外一个崭新的关注点是反应式编程,它致力于通过非阻塞操作提供更好的扩展性并提升性能。

1.1 什么是Spring

  • Spring的核心是提供了一个容器(container),通常称为Spring应用上下文(Spring application context),它们会创建和管理应用组件。这些组件也可以称为bean,会在Spring应用上下文中装配在一起,从而形成一个完整的应用程序。
  • 应用组件通过Spring的应用上下文来进行管理并实现互相注入
  • 在历史上,指导Spring应用上下文将bean装配在一起的方式是使用一个或多个XML文件(描述各个组件以及它们与其他组件的关联关系)
  • 在最近的Spring版本中,基于Java的配置更为常见。
  • 在Spring技术中,自动配置起源于所谓的自动装配(autowiring)和组件扫描(component scanning)。
  • Spring Boot大幅度减少了构建应用所需的显式配置的数量(不管是XML配置还是Java配置)
  • 因为Spring XML配置是一种过时的方式,所以我们主要关注Spring基于Java的配置。

1.2 初始化Spring应用

  • 使用Spring Initializr初始化应用
  • Spring Initializr是一个基于浏览器的Web应用,同时也是一个REST API,能够生成一个Spring项目结构的骨架
  • mvnw和mvnw.cmd:这是Maven包装器(wrapper)脚本。借助这些脚本,即便你的机器上没有安装Maven,也可以构建项目。
  • 打包为JAR文件是基于云思维做出的选择
  • 请留意元素,更具体来说是它的子元素。这表明我们的项目要以spring-boot-starter-parent作为其父POM。除了其他的一些功能之外,这个父POM为Sprin
  • Spring Boot starter依赖的特别之处在于它们本身并不包含库代码,而是传递性地拉取其他的库。这种starter依赖主要有3个好处。
  • 因为我们将会通过可执行JAR文件的形式来运行应用,所以很重要的一点就是要有一个主类,它将会在JAR运行的时候被执行。
  • @SpringBootApplication是一个组合注解,它组合了3个其他的注解。
  • 最好还是要为没有实现自动配置的功能创建一个单独的配置类。
  • @RunWith是JUnit的注解,它会提供一个测试运行器(runner)来指导JUnit如何运行测试。
  • SpringRunner是SpringJUnit4ClassRunner的别名,是在Spring 4.3中引入的,以便于移除对特定JUnit版本的关联(比如,JUnit 4)
  • @SpringBootTest会告诉JUnit在启动测试的时候要添加上Spring Boot的功能。
  • @RunWith(SpringRunner.class)和@SpringBootTest会为测试加载Spring应用上下文

1.3 编写Spring应用

  • 控制器是处理请求并以某种方式进行信息响应的类
  • @Controller并没有做太多的事情。它的主要目的是让组件扫描将这个类识别为一个组件
  • 这个值将会被解析为视图的逻辑名
  • 模板名称是由逻辑视图名派生而来的,再加上“/templates/”前缀和“.html”后缀。最终形成的模板路径将是“/templates/home.html”。
  • ymeleaf的th:src属性和@{...}表达式,以便于引用相对于上下文路径的图片。除此之外,它
  • @WebMvcTest注解。这是Spring Boot所提供的一个特殊测试注解,它会让这个测试在Spring MVC应用的上下文中执行
  • Spring Boot应用的习惯做法是将所有它需要的东西都放到一起,没有必要将其部署到某种应用服务器中
  • 代码变更后应用会自动重启; •当面向浏览器的资源(如模板、JavaScript、样式表)等发生变化时,会自动刷新浏览器; •自动禁用模板缓存; •如果使用H2数据库的话,内置了H2控制台。
  • 当DevTools运行的时候,应用程序会被加载到Java虚拟机(Java virtual Machine,JVM)两个独立的类加载器中。其中一个类加载器会加载你的Java代码、属性文件以及项目中“src/main/”路径下几乎所有的内容。这些条目很可能会经常发生变化。另外一个类加载器会加载依赖的库,这些库不太可能经常发生变化。
  • DevTools通过禁用所有模板缓存解决了这个问题。
  • DevTools在运行的时候,它会和你的应用程序一起,同时自动启动一个LiveReload服务器。LiveReload服务器本身并没有太大的用处。但是,当它与LiveReload浏览器插件结合起来的时候,就能够在模板、图片、样式表、JavaScript等(实际上,几乎涵盖为浏览器提供服务的所有内容)发生变化的时候自动刷新浏览器。
  • Spring(以及Spring Boot)可以视为感受不到框架的框架(frameworkless framework)。
  • •在Spring应用上下文中配置bean以启用Spring MVC;•在Spring应用上下文中配置嵌入式的Tomcat服务器;•配置Thymeleaf视图解析器,以便于使用Thymeleaf模板渲染Spring MVC视图。

1.4 俯瞰Spring风景线

  • Spring核心框架是Spring领域中一切的基础。它提供了核心容器和依赖注入框架,另外还提供了一些其他重要的特性。
  • Spring核心框架还提供了一些对数据持久化的基础支持,尤其是基于模板的JDBC支持。
  • Spring WebFlux的新反应式Web框架
  • starter依赖和自动配置
  • Actuator能够洞察应用运行时的内部工作状况,包括指标、线程dump信息、应用的健康状况以及应用可用的环境属性
  • 将应用程序的数据repository定义为简单的Java接口,在定义驱动存储和检索数据的方法时使用一种命名约定即可。
  • Spring Security解决了应用程序通用的安全性需求,包括身份验证、授权和API安全性。
  • Spring Integration解决了实时集成问题
  • 使用由微服务组成的多个独立部署单元来组合形成应用程序
  • 要更全面地研究Spring Cloud,我建议阅读John Carnell的Spring Microservices in Action一书[SPAN](Manning,2017)。

1.5 小结

  • Spring Boot构建在Spring之上,通过简化依赖管理、自动配置和运行时洞察,使Spring更加易用

第2章 开发Web应用

  • 内在固然非常重要,但是外在的,也就是第一眼看到的东西同样非常重要。

2.1 展现信息

  • 在Spring Web应用中,获取和处理数据是控制器的任务,而将数据渲染到HTML中并在浏览器中展现则是视图的任务
  • 应用的领域指的是它所要解决的主题范围:也就是会影响到对应用理解的理念和概念
  • @RequiredArgsConstructor
  • 此外还因为我们使用了名为Lombok的库(这是一个非常棒的库,它能够在运行时动态生成这些方法)
  • 但是,我们还需要将Lombok作为扩展添加到IDE上,否则IDE将会报错,提示缺少方法和final属性没有赋值
  • 它们的主要职责是处理HTTP请求,要么将请求传递给视图以便于渲染HTML(浏览器展现),要么直接将数据写入响应体(RESTful)
  • 首先是@Slf4j,这是Lombok所提供的注解,在运行时,它会在这个类中自动生成一个SLF4J(Simple Logging Facade for Java)Logger。
  • 这个注解会将这个类识别为控制器,并且将其作为组件扫描的候选者,所以Spring会发现它并自动创建一个DesignTacoController实例,并将该实例作为Spring应用上下文中的bean。
  • 当@RequestMapping注解用到类级别的时候,它能够指定该控制器所处理的请求类型。
  • @GetMapping结合类级别的@RequestMapping,指明当接收到对“/design”的HTTP GET请求时,将会调用showDesignForm()来处理请求。
  • 表2.1 Spring MVC的请求映射注解
  • 在为控制器方法声明请求映射时,越具体越好。这意味着至少要声明路径(或者从类级别的@RequestMapping继承一个路径)以及它所处理的HTTP方法。
  • 通常,我喜欢只在类级别上使用@RequestMapping,以便于指定基本路径。在每个处理器方法上,我会使用更具体的@GetMapping、@PostMapping等注解。
  • Model对象负责在控制器和展现数据的视图之间传递数据。实际上,放到Model属性中的数据将会复制到Servlet Response的属性中,这样视图就能在这里找到它们了。
  • 在运行时,Spring Boot的自动配置功能会发现Thymeleaf在类路径中,因此会为Spring MVC创建支撑Thymeleaf视图的bean。
  • 它们可以与Servlet的request属性协作
  • Thymeleaf模板就是增加一些额外元素属性的HTML,这些属性能够指导模板如何渲染request数据
  • mvn spring-boot:run构建命令来运行应用

2.2 处理表单提交

  • 当表单提交的时候,表单中的输入域会绑定到Taco对象(这个类会在下面的程序清单中进行介绍)的属性中
  • Taco类也添加了@Data注解,会在编译期自动生成必要的JavaBean方法,所以这些方法在运行期是可用的。
  • 表单中的这些输入域直接对应Taco类的ingredients和name属性。
  • redirect:”前缀,表明这是一个重定向视图。

2.3 校验表单输入

  • Spring支持Java的Bean校验API(Bean Validation API,也被称为JSR-303)
  • 它使用@NotNull和@Size注解来声明这些校验规则。
  • @CreditCardNumber注解。这个注解声明该属性的值必须是合法的信用卡号,它要能通过Luhn算法的检查。
  • @Pattern注解并为其提供了一个正则表达式
  • @Digits注解,能够确保它的值包含3位数字
  • @Valid注解会告诉Spring MVC要对提交的Taco对象进行校验,而校验时机是在它绑定完表单数据之后、调用processDesign()之前
  • Thymeleaf提供了便捷访问Errors对象的方法,这就是借助fields及其th:errors属性。
  • fields属性的hasErrors()方法会检查ccNumber域是否存在错误,如果存在,就将会渲染

2.4 使用视图控制器

  • 视图控制器:也就是只将请求转发到视图而不做其他事情的控制器。
  • WebMvcConfigurer定义了多个方法来配置Spring MVC。尽管只是一个接口,但是它提供了所有方法的默认实现,只需要覆盖所需的方法即可
  • 所有的配置类都可以实现WebMvcConfigurer接口并覆盖addViewController方法
  • 我倾向于为每种配置(Web、数据、安全等)创建新的配置类,这样能够保持应用的引导配置类尽可能地整洁和简单。

2.5 选择视图模板库

  • Spring Boot会探测到你所选择的模板库,并自动配置为Spring MVC控制器生成视图所需的各种组件。
  • Java Servlet容器包括嵌入式的Tomcat和Jetty容器,通常会在“/WEB-INF”目录下寻找JSP。如果我们将应用构建成一个可执行的JAR文件,就无法满足这种需求了。因此,只有在将应用构建为WAR文件并部署到传统的Servlet容器中时,才能选择JSP方案。如果你想要构建可执行的JAR文件,那么必须选择Thymeleaf、FreeMarker或表2.2中的其他方案。
  • 默认情况下,模板只有在第一次使用的时候解析一次,解析的结果会被后续的请求所使用。
  • 唯一需要注意的是,在将应用部署到生产环境之前,一定要删除这一行代码(或者将其设置为true)

2.6 小结

  • 对于没有模型数据和逻辑处理的HTTP GET请求,可以使用视图控制器。

第3章 使用数据

  • JDBC(Java Database Connectivity)

3.1 使用JDBC读取和写入数据

  • 在处理关系型数据的时候,Java开发人员有多种可选方案,其中最常见的是JDBC和JPA。
  • Spring对JDBC的支持要归功于JdbcTemplate类
  • SQLException是一个检查型异常,它需要在catch代码块中进行处理。
  • 在将对象持久化到数据库的时候,通常最好有一个字段作为对象的唯一标识。
  • 当Spring创建JdbcIngredientRepository bean的时候,它会通过@Autowired标注的构造器将JdbcTemplate注入进来
  • query()会接受要执行的SQL以及Spring RowMapper的一个实现(用来将结果集中的每行数据映射为一个对象)
  • queryForObject()方法的运行方式和query()非常类似,只不过它只返回一个对象,而不是对象的List。
  • 如果在应用的根类路径下存在名为schema.sql的文件,那么在应用启动的时候将会基于数据库执行这个文件中的SQL。
  • 直接使用update()方法。•使用SimpleJdbcInsert包装器类。
  • 类级别的@SessionAttributes能够指定模型对象(如订单属性)要保存在session中,这样才能跨请求使用。
  • Order参数带有@ModelAttribute注解,表明它的值应该是来自模型的,SpringMVC不会尝试将请求参数绑定到它上面。
  • processOrder()方法请求了一个SessionStatus参数,并调用了它的setComplete()方法来重置session。

3.2 使用Spring Data JPA持久化数据

  • Spring Data JPA:基于关系型数据库进行JPA持久化。
  • 这个starter依赖不仅会引入Spring Data JPA,还会传递性地将Hibernate作为JPA实现引入进来
  • 如果你想要使用不同的JPA实现,那么至少需要将Hibernate依赖排除出去并将你所选择的JPA库包含进来。
  • 为了将Ingredient声明为JPA实体,它必须添加@Entity注解。它的id属性需要使用@Id注解,以便于将其指定为数据库中唯一标识该实体的属性。
  • 因为我们要依赖数据库自动生成ID值,所以在这里还为id属性设置了@GeneratedValue,将它的strategy设置为AUTO。
  • @PrePersist注解。在Taco持久化之前,我们会使用这个方法将createdAt设置为当前的日期和时间
  • @Table。它表明Order实体应该持久化到数据库中名为Taco_Order的表中。
  • CrudRepository定义了很多用于CRUD(创建、读取、更新、删除)操作的方法。注意,它是参数化的,第一个参数是repository要持久化的实体类型,第二个参数是实体ID属性的类型。
  • 本质上,Spring Data定义了一组小型的领域特定语言(Domain-Specific Language,DSL),在这里持久化的细节都是通过repository方法的签名来描述的。
  • repository方法是由一个动词、一个可选的主题(Subject)、关键词By以及一个断言所组成的
  • Spring Data会将get、read和find视为同义词,它们都是用来获取一个或多个实体的
  • 除了Equals和Between操作之外,Spring Data方法签名还能包括如下的操作符:

4.1 启用Spring Security

  • 当应用启动的时候,自动配置功能会探测到Spring Security出现在了类路径中,因此它会初始化一些基本的安全配置。
  • •所有的HTTP请求路径都需要认证;•不需要特定的角色和权限;•没有登录页面;•认证过程是通过HTTP basic认证对话框实现的;•系统只有一个用户,用户名为user。

4.2 配置Spring Security

  • Spring Security为配置用户存储提供了多个可选方案,包括: •基于内存的用户存储; •基于JDBC的用户存储; •以LDAP作为后端的用户存储; •自定义用户详情服务。
  • AuthenticationManagerBuilder使用构造者(builder)风格的接口来构建认证细节。
  • passwordEncoder()方法指定一个密码转码器(encoder):
  • 不管你使用哪一个密码转码器,都需要理解一点,即数据库中的密码是永远不会解码的。
  • 使用LDAP(LightweightDirectory Access Protocol,轻量级目录访问协议)访问的用户存储。
  • 基于LDAP认证的默认策略是进行绑定操作,直接通过LDAP服务器认证用户。
  • 通过实现UserDetails接口,我们能够提供更多信息给框架,比如用户都被授予了哪些权限以及用户的账号是否可用。
  • encoder()方法带有@Bean注解,它将用来在Spring应用上下文中声明PasswordEncoder bean。对于encoder()的任何调用都会被拦截,并且会返回应用上下文中的bean实例。

4.3 保护Web请求

  • 这些规则的顺序是很重要的。声明在前面的安全规则比后面声明的规则有更高的优先级
  • and()方法表示我们已经完成了授权相关的配置,并且要添加一些其他的HTTP配置。在开始新的配置区域时,我们可以多次调用and()。
  • 当Spring Security断定用户没有认证并且需要登录的时候,它就会将用户重定向到该路径。
  • 跨站请求伪造(Cross-Site Request Forgery,CSRF)
  • 我们唯一需要做的就是确保应用中的每个表单都要有一个名为“_csrf”的字段,它会持有CSRF token。

4.4 了解用户是谁

  • 尽管这个代码片段充满了安全性相关的代码,但是它与前文所述的其他方法相比有一个优势:它可以在应用程序的任何地方使用,而不仅仅是在控制器的处理器方法中。这使得它非常适合在较低级别的代码中使用。

第5章 使用配置属性

  • 配置属性只是Spring应用上下文中bean的属性而已,它们可以通过多个源进行设置,包括JVM系统属性、命令行参数以及环境变量。

5.1 细粒度的自动配置

  • •bean装配:声明在Spring应用上下文中创建哪些应用组件以及它们之间如何互相注入的配置。•属性注入:设置Spring应用上下文中bean的值的配置。
  • 在基于Java的配置中,带有@Bean注解的方法一般会同时初始化bean并立即为它的属性设置值
  • Spring环境会拉取多个属性源,包括: •JVM系统属性; •操作系统环境变量; •命令行参数; •应用属性配置文件。
  • Spring环境从各个属性源拉取属性,并让Spring应用上下文中的bean可以使用它们
  • 如果你希望应用始终在一个特定的端口启动,那么可以通过操作系统的环境变量进行一次性的设置:
  • 如果我们设置了spring.datasource.jndi-name属性,其他的数据库连接属性(已经设置了的话)就会被忽略掉。
  • 尽管我们将server.port属性显式设置成了0,但是服务器并不会真的在端口0上启动。相反,它会任选一个可用的端口。
  • 默认情况下,Spring Boot通过Logback配置日志,日志会以INFO级别写入到控制台中。
  • 借助Spring Boot的配置属性功能,我们不用创建logback.xml文件就能完成这些变更。

5.2 创建自己的配置属性

  • Pageable是Spring Data根据页号和每页数量选取结果的子集的一种方法
  • @ConfigurationProperties注解。它的prefix属性设置成了taco.orders,这意味着当设置pageSize的时候,我们需要使用名为taco.orders.pageSize的配置属性。
  • 如果在生产环境中需要快速更改,我们可以将taco.orders.pageSize设置为环境变量,这样就不用重新构建和重新部署应用了:
  • @ConfigurationProperties实际上通常会放到一种特定类型的bean中,这种bean的目的就是持有配置数据
  • 为了创建自定义配置属性的元数据,我们需要在META-INF下创建一个名为additional-spring-configuration-metadata.json的文件(比如,在项目的“src/main/resources/ META-INF”目录下)。

5.3 使用profile进行配置

  • profile是一种条件化的配置,在运行时,根据哪些profile处于激活状态,可以使用或忽略不同的bean、配置类和配置属性。
  • 定义特定profile相关的属性的另外一种方式仅适用于YAML配置。它会将特定profile的属性和非profile的属性都放到application.yml中,它们之间使用3个中划线进行分割,并且使用spring.profiles属性来命名profile。
  • 要激活某个profile,需要做的就是将profile名称的列表赋值给spring.profiles.active属性。
  • 假设我们希望某些bean仅在特定profile激活的情况下才需要创建。在这种情况下,@Profile注解可以将某些bean设置为仅适用于给定的profile。

6.1 编写RESTful控制器

  • @RestController注解会告诉Spring,控制器中的所有处理器方法的返回值都要直接写入响应体中,而不是将值放到模型中并传递给一个视图以便于进行渲染。
  • @RequestMapping注解还设置了一个produces属性。这指明DesignTacoController中的所有处理器方法只会处理Accept头信息包含“application/json”的请求
  • Spring借助@CrossOrigin注解让CORS的使用更加简单。正如我们所看到的,@CrossOrigin允许来自任何域的客户端消费该API。
  • consumes属性用于指定请求输入,而produces用于指定请求输出
  • @RequestBody注解能够确保请求体中的JSON会被绑定到Taco对象上。
  • 在适当的地方使用@ResponseStatus将最具描述性和最精确的HTTP状态码传递给客户端是一种更好的做法。
  • PUT真正的目的是执行大规模的替换(replacement)操作,而不是更新操作。HTTP PATCH的目的是对资源数据打补丁或局部更新。
  • 这里需要关注的第一件事情就是patchOrder()方法使用了@PatchMapping注解,而不是@PutMapping注解,这表示它应该处理HTTP PATCH请求,而不是PUT请求。
  • 尽管PATCH在语义上代表局部更新,但是在处理器方法中实际编写代码执行更新的还是我们自己。

6.2 启用超媒体

  • 超媒体作为应用状态引擎(Hypermedia as the Engine of Application State,HATEOAS)是一种创建自描述API的方式。API所返回的资源中会包含相关资源的链接,客户端只需要了解最少的API URL信息就能导航整个API。
  • 如果API启用了超媒体功能,那么API将会描述自己的URL,从而减轻客户端对其进行硬编码的痛苦。
  • 这种特殊风格的HATEOAS被称为HAL(超文本应用语言,Hypertext Application Language)。这是一种在JSON响应中嵌入超链接的简单通用格式。
  • 在Spring HATEOAS中,最有用的链接构建者是ControllerLinkBuilder。这个链接构建者非常智能,它能自动探知主机名是什么,这样就能避免对其进行硬编码。同时,它还提供了流畅的API,允许我们相对于控制器的基础URL构建链接。
  • @Relation注解能够帮助我们消除JSON字段名和Java代码中定义的资源类名之间的耦合。

6.3 启用数据后端服务

  • Spring Data REST是Spring Data家族中的另外一个成员,它会为Spring Data创建的repository自动生成REST API。

第8章 发送异步消息

  • 异步消息是一个应用程序向另一个应用程序间接发送消息的一种方式,这种间接性能够为进行通信的应用带来更松散的耦合和更大的可伸缩性。
  • Spring提供的3种异步消息方案:Java消息服务(Java Message Service,JMS)、RabbitMQ和高级消息队列协议(Advanced Message Queueing Protocol)、Apache Kafka。

8.1 使用JMS发送消息

  • Spring通过基于模板的抽象为JMS功能提供了支持,这个模板就是JmsTemplate。
  • Artemis是重新实现的下一代ActiveMQ,使ActiveMQ变成了遗留方案。
  • 要创建能够对JMS消息做出反应的消息监听器,我们需要为组件中的某个方法添加@JmsListener注解。

8.3 使用Kafka的消息

  • Kafka仅使用主题实现消息的发布/订阅。
  • Kafka主题会复制到集群的所有代理上。集群中的每个节点都会担任一个或多个主题的首领(leader),负责该主题的数据并将其复制到集群中的其他节点上。

9.1 声明一个简单的集成流

  • @MessagingGateway注解。这个注解会告诉Spring Integration要在运行时生成该接口的实现

10.1 反应式编程概览

  • 反应式流旨在提供无阻塞回压的异步流处理标准。
  • 通过回压,数据消费者可以限制它们想要处理的数据数量,避免被过快的数据源所淹没。
  • Java的流通常都是同步的,并且只能处理有限的数据集。从本质上来说,它们只是使用函数来对集合进行迭代的一种方式。
  • 反应式流规范可以总结为4个接口:Publisher、Subscriber、Subscription和Processor。Publisher负责生成数据,并将数据发送给Subscription(每个Subscriber对应一个Subscription)。
  • Reactor项目是反应式流规范的一个实现,提供了一组用于组装反应式流的函数式API。

10.2 初识Reactor

  • 反应式编程意味着要构建数据将要流经的管道。当数据流经管道时,可以对它们进行某种形式的修改或者使用。
  • Flux代表具有零个、一个或者多个(可能是无限个)数据项的管道。Mono是一种特殊的反应式类型,针对数据项不超过一个的场景,它进行了优化。
  • 反应式流程通常使用弹珠图(marble diagram)表示

10.3 使用常见的反应式操作

  • 订阅反应式类型就如同你打开数据流的水龙头。
  • 因为mergeWith()方法不能完美地保证源Flux之间的先后顺序,所以我们可以考虑使用zip()方法
  • 在每个数据项被源Flux发布时,map操作是同步执行的,如果你想要异步地转换过程,那么你应该考虑使用flatMap操作。
  • subscribe()方法是一个动词,订阅并驱动反应式流;而subscribeOn()方法则更具描述性,指定了如何并发地处理订阅。
  • 使用flatMap()和subscribeOn()的好处是:我们可以在多个并行线程之间拆分工作,从而增加流的吞吐量。因为工作是并行完成的,无法保证哪项工作首先完成,所以结果Flux中数据项的发布顺序是未知的。
  • 当组合使用buffer()方法和flatMap()方法时,我们可以对每个List集合进行并行处理

11.1 使用Spring WebFlux

  • 异步的Web框架能够以更少的线程获得更高的可扩展性,通常它们只需要与CPU核心数量相同的线程。通过使用所谓的事件轮询(event looping)机制(如图11.1所示),这些框架能够用一个线程处理很多请求,这样每次连接的成本会更低。
  • WebFlux的默认嵌入式服务器是Netty而不是Tomcat。
  • Spring WebFlux的控制器方法要接受和返回反应式类型,如Mono和Flux,而不是领域类型和集合
  • Spring WebFlux是真正的反应式Web框架,允许在事件轮询中处理请求;而Spring MVC是基于Servlet的,依赖于多线程来处理多个请求。

11.2 定义函数式请求处理器

  • 所有基于注解的编程方式都会存在注解该做什么以及注解如何做之间的割裂

11.4 反应式消费REST API

  • Spring 5提供了WebClient,它可以作为RestTemplate的反应式版本。WebClient能够让我们请求外部API时发送和接收反应式类型。

13.1 思考微服务

  • 微服务架构是一种分布式架构,有自己需要应对的挑战,包括网络延迟。在迁移至微服务架构时,我们需要记住这一点,因为很多的远程调用会累积并降低应用的速度。

13.2 搭建服务注册中心

  • Ribbon是一个客户端负载均衡器,它会在每个客户端上发起请求。
  • Eureka的默认行为是与其他Eureka服务器建立关联,尝试获取其他Eureka服务器的服务注册中心,甚至还会将自身注册为其他Eureka服务器的服务。

13.3 注册和发现服务

  • 将端口设置成0的话,应用会选择任意一个可用端口来启动。
  • 我们有两种方式可以消费从Eureka中查找到的服务:•支持负载均衡的RestTemplate;•Feign生成的客户端接口。
  • Feign是一个REST客户端库,使用一种特殊的、接口驱动的方式来定义REST客户端。

14.1 共享配置

  • Spring Cloud Config Server提供了中心化的配置功能,应用中的所有微服务均可以依赖该服务器来获取配置。因为它是中心化的,所以是一个一站式的配置商店,所有的服务都可以使用它,另外它还能够为特定服务提供专门的配置。

15.2 声明断路器

  • 任何使用@HystrixCommand注解的方法都会为其声明一个断路器切面。
  • 当遇到失败的时候,微服务应该应用维加斯规则(Vegas Rule):在微服务中发生的事情,就留在微服务中。