《深入浅出Spring Boot 2.x》笔记

1 概述

1.1 优点

  1. 创建独立的Spring应用程序;
  2. 嵌入的Tomcat、Jetty或者Undertow,无须部署WAR文件;
  3. 允许通过Maven来根据需要获取starter;
  4. 尽可能地自动配置Spring;
  5. 提供生产就绪型功能,如指标、健康检查和外部配置;
  6. 绝对没有代码生成,对XML没有要求配置。

1.2 Spring Boot初试

1.2.1 代码

  1. 主程序:

    package com.springboot.chapter1.main;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @SpringBootApplication
    @Controller
    public class Chapter1Main {
    	
    	public static void main(String[] args) {
    		SpringApplication.run(Chapter1Main.class, args);
    	}
    	
    	@RequestMapping("/test")
    	@ResponseBody
    	public Map<String, String> test() {
    		Map<String, String> map = new HashMap<>();
    		map.put("key1", "value1");
    		return map;
    	}
    }
    
  2. 依赖:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>boot</groupId>
    	<artifactId>chapter1</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>chapter1 Maven Webapp</name>
    	<url>http://maven.apache.org</url>
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.0.0.RELEASE</version>
    	</parent>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>3.8.1</version>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    	<build>
    		<finalName>chapter1</finalName>
    	</build>
    </project>
    
  3. 前端:

    <html>
    <body>
    <h2>Hello World!</h2>
    </body>
    </html>
    

1.2.2 效果

在这里插入图片描述

第二章

2.3 使用自定义配置

Spring Boot的参数配置除了properties文件之外,还可以使用yml文件等,它会以下列的优先级顺序进行加载:

  • 命令行参数
  • 来自java:comp/env 的JNDI属性
  • Java系统属性(System.getProperties())
  • 操作系统环境变量
  • RandomValuePropertySource配置的random.*属性值
  • jar包外部的application-{profile}.properties 或 application.yml(带spring.profile)配置文件
  • jar包内部的application-{profile}.properties 或 application.yml(带spring.profile)配置文件
  • jar包外部的application.properties 或 application.yml(不带spring.profile)配置文件
  • jar包内部的application.properties 或 application.yml(不带spring.profile)配置文件
  • @Configuration注解类上的@PropertySource
  • 通过SpringApplication.setDefaultProperties指定的默认属性

第三章

IoC是一种通过描述来生成或者获取对象的技术。

IoC容器需要具备两个基本的功能:

  • 通过描述管理Bean,包括发布和获取Bean;
  • 通过描述完成Bean之间的依赖关系;

3.3.1 注解@Autowired

@Autowired提供这样的规则,首先它会根据类型找到对应的Bean,如果对应类型的Bean不是唯一的,那么它会根据其属性名称和Bean的名称进行匹配。如果匹配得上,
就会使用该Bean;如果还无法匹配,就会抛出异常。

@Autowired是一个默认必须找到对应Bean的注解,如果不能确认其标注属性一定会存在并且允许这个被标注的属性为null,那么可以配置@Autowired属性required为false。

3.3.2 消除歧义性 — @Primary 和 @Qualifier

@Primary的作用是:告诉Spring IoC容器,当发现有多个同样类型的Bean时,请优先使用加了@Primary的Bean。
@Qualifier的作用是:它的配置项value需要一个字符串去定义,它将与@Autowired组合在一起,通过类型和名称一起找到Bean。

第六章

6.3.2 详解隔离级别

未提交读

其含义是:允许一个事务读取另一个事务没有提交的数据。未提交读是一种危险的隔离级别,所以一般在我们实际的开发中应用不广,但是它的优点在于并发能力高,适合
那些对数据一致性没有要求而追求高并发的场景,它的最大坏处是出现脏读。

读写提交

其含义是:一个事务只能读取另外一个事务已经提交的数据,不能读取未提交的数据。(解决了脏读的问题,但是出现不可重读的问题)

可重复读

可重复读的目标是克服读写提交中出现的不可重复读的现象,因为在读写提交的时候,可能出现一些值的变化,影响当前事务的执行。(解决了不可重复读的问题,但是会有幻读的问题)

串行化

串行化是数据库最高的隔离级别,它会要求所有的SQL都按照顺序执行,这样就可以克服上述隔离级别出现的各种问题,所以它能够完全保证数据的一致性。

不同数据库的支持不一样。例如,Oracle只能支持读写提交和串行化,而MySQL则能够支持4种,对于Oracle默认的隔离级别为读写提交,MySQL则是可重复读,这些需要根据具体数据库来决定。

第七章

7.3.4 使用Lua脚本

使用Redis的Lua语言来保证数据的一致性,且Lua脚本具备强大的运算功能,在高并发需要保证数据一致性时,Lua脚本方案比使用Redis自身提供的事务要好一些。

在Redis中有两种运行Lua的方法:

  1. 直接发送Lua到Redis服务器去执行
  2. 先把Lua发送给Redis,Redis会对Lua脚本进行缓存,然后返回一个SHA1的32编码回来,之后只需要发送SHA1和相关参数给Redis便可以执行了。
为什么会存32位编码执行的方法?

因为,如果Lua脚本很长,那么需要通过网络传递脚本给Redis去执行了,而现实的情况是:网络的传递速度往往跟不上Redis的执行速度,所以网络就会成为
Redis执行的瓶颈。如果只是传递32位编码和参数,那么需要传递的消息就少了许多,这样就可以极大地减少网络传输的内容,从而提升性能。

7.4.1 缓存管理器和缓存的启用

缓存管理器配置
spring.cache.cache-names = # 如果由底层的缓存管理器支持创建,以逗号分隔的列表来缓存名称
spring.cache.caffeine.spec = # caffeine缓存配置细节
spring.cache.couchbase.expiration=0ms # couchbase缓存超时时间,默认是永不超时
spring.cache.chcache.config= # 配置ehcache缓存初始化文件路径
spring.cache.infinispan.config= # infinispan缓存配置文件
spring.cache.jcache.config= # jcache缓存配置文件
spring.cache.jcache.provider = # jcache缓存提供者配置
spring.cache.redis.cache-null-vaues=true # 是否允许Redis缓存空值
spring.cache.redis.key-prefix= # Redis的键前缀
spring.cache.redis.time-to-live=0ms # 缓存超时时间戳,配置为0则不设置超时时间
spring.cache.redis.use-key-prefix=true # 是否启用Redis的键前缀
spring.cache.type= # 缓存类型,在默认的情况下,Spring会自动根据上下文探测

7.4.2 开发缓存注解

@CachePut:表示将方法结果返回存放到缓存中
@Cacheable:表示先从缓存中通过定义的键查询,如果可以查询到数据,则返回,否则执行该方法,返回数据,并且将返回结果保存到缓存中
@CacheEvict:通过定义的键移除缓存,它有一个Boolean类型的配置项beforeInvocation,表示在方法之前或者之后移除缓存。因为其默认值为false,所以默认为方法之后将缓存移除。

第八章

MongoDB是由C++语言编写的一种NoSQL,是一个基于分布式文件存储的开源数据库系统。在负载高时可以添加更多的节点,以保证服务器性能,MongoDB的目的是为
Web应用提供可扩展的高性能数据存储解决方案。MongoDB将数据存储为一个文档,数据结构由键值对组成,这里的MongoDB文档类似于JSON数据集,所以很容易转化
成为Java POJO对象或者JavaScript对象,这些字段值还可以包含其他文档、数组及文档数组。

第十章

10.2.2 使用@RequestParam获取参数

注解@RequestParam用来确定前后端参数名称的映射关系;默认情况下,@RequestParam标注的参数是不能为空的,为了让它能够为空,可以配置其属性为false。

@RequestParam(value = "id", required = false) Long id

10.2.5 通过URL传递参数

可以通过处理器映射和注解@PathVariable的组合获取URL参数。首先通过处理器映射可以定位参数的位置和名称,而@PathVariable则可以通过名称来获取参数。

10.2.6 获取格式化参数

@DateTimeFormat 和 @NumberFormat 分别可以对日期和数字请求参数进行格式化

在SpringBoot中,日期参数的格式化也可以不使用@DateTimeFormat,而只在配置文件application.properties中加入如下参数即可:

spring.mvc.date-format=yyyy-MM-dd

10.3.1 处理器获取参数逻辑

当一个请求来到时,在处理器执行的过程中,它首先会从HTTP请求和上下文环境来得到参数。如果是简易的参数,它会以简单的转换器进行转换,而这些简单的转换器是
SpringMVC自身已经提供了的。但是如果是转换HTTP请求体(Body),它就会调用 HTTPMessageConvert 接口的方法对请求体的信息进行转换,首先它会判断
能否对请求体进行转换,如果可以就会将其转换成Java类型。

控制器方法的参数标注了@RequestBody,所以处理器会采用请求体(Body)的内容进行参数转换,而前端的请求体为JSON类型,所以首先它会调用canRead方法来确定
请求体是否可读。如果判断可读后,接着就是使用read方法,将前端提交的用户JSON类型的请求体转换成控制器的类参数,这样控制器就能够得到参数了。

处理器转换参数的过程:
在SpringMVC中,是通过 WebDataBinder机制 来获取参数的,它的主要作用是:解析HTTP请求的上下文,然后在控制器调用之前转换参数并且提供验证的功能,
为调用控制器方法做准备。处理器会从HTTP请求中读取数据,然后通过是那种接口来进行型各类参数转换,这三种接口是:Converter、Formatter 和 GenericConverter
在SpringMVC的机制中,这三种接口的实现类都采用了注册机的机制,默认的情况下SpringMVC已经在注册即将内注册了许多的转换器,这样就可以实现大部分的数据类型的转换,
所以在大部分的情况下无须开发者再提供转换器。

10.4.2 参数验证机制

为了能够更加灵活地提供验证机制,Spring还提供自己的验证机制。在参数转换时,可以看到在SpringMVC中,存在WebDataBinder机制进行管理,在默认的情况下
Spring会自动地根据上下文通过注册了的转换器转换出控制器所需的参数。在WebDataBinder中,除了可以注册转换器外,还允许注册验证器(Validator)。

Validator验证器接口,它定义了两个方法,其中supports方法参数为需要验证的POJO类型,如果该方法返回true,则Spring会使用当前验证器的validate方法
去验证POJO。而validation方法包含需要的target对象和错误对象errors,其中target是参数绑定后的POJO,这样便可以通过这个参数对象进行业务逻辑的自定义
校验。如果发现错误,则可以保存到errors对象中,然后返回给控制器。

10.5 数据模型

在Spring MVC的应用中,如果在控制器方法的参数中使用ModelAndView、Model或者ModelMap作为参数类型,Spring MVC会自动创建数据模型对象。

10.6 视图和视图解析器

在Spring MVC中分为:逻辑视图非逻辑视图。逻辑视图是需要 视图解析器(ViewResolver) 进行进一步定位的。对于非逻辑视图,则并不需要
进一步地定位视图的位置,它只需要直接将数据模型渲染出来即可。

10.6.1 视图设计

对于视图,除了JSON和JSP视图之外,还有其他类型的视图,如Excel、PDF等。虽然视图具有多样性,但是它们都会实现Spring MVC定义的视图接口View。

10.7.1 Spring MVC对文件上传的支持

DispatcherServlet 会使用 适配器模式,将 HttpServletRequest接口对象 转换成 MultipartHttpServletRequest对象
MultipartHttpServletRequest接口扩展了HTTPServletRequest接口的所有方法,而且定义了一些操作文件的方法,这样通过这些方法就可以实现对上传文件的操作。

只是在使用Spring MVC上传文件时,还需要配置MultipartHttpServletRequest,这个任务是通过MultipleResolver接口实现的。对于MultipleResolver接口,
它又存在两个实现类,这两个实现类分别是 StandardServletMultipleResolver 和 CommonsMultipleResolver,可以使用它们中的任意一个来实现文件上传。
在默认的情况下Spring推荐使用的是 StandardServletMultipleResolver,因为它只需要依赖于Servlet API提供的包,而对于 CommonsMultipleResolver,
则需要依赖于Apache提供的第三方包来实现,这显然没有 StandardServletMultipleResolver来得实在。从实用的角度来说,因为Spring3.1之后已经能够支持
StandardServletMultipleResolver,所以 CommonsMultipleResolver已经逐渐被废弃了。

10.10 Spring MVC拾遗

10.10.1 @ResponseBody转换成JSON的秘密

在进入控制器方法前,当遇到标注的@ResponseBody后,处理器就会记录这个方法的响应类型为JSON数据集。当执行完控制器返回后,处理器会启用结果解析器(ResultResolver)
去解析这个结果,它会去轮询注册给Spring MVC的 HttpMessageConverter接口的实现类。因为 MappingJackson2HttpMessageConverter这个实现类已经被Spring MVC
所注册,加上Spring MVC将控制器的结果类型表明为JSON,所以就匹配上了,于是通过它就在处理器内部把结果转换为了JSON。当然有时候会轮询不到匹配的HttpMessageConverter
,那么它就会交由Spring MVC后续流程去处理。如果控制器返回结果被MappingJason2HttpMessageConverter进行了转换,那么后续的模型和视图(ModelAndView)
就返回null,这样视图解析器和视图渲染将不再被执行。

10.10.2

首先,被addFlashAttribute方法保存的参数,在控制器执行完成后,会被保存到Session对象中。当执行重定向时,在进入重定向前首先把Session中的参数取出,用
以填充重定向方法的参数和数据模型,之后删除Session中的数据,然后就可以调用重定向方法,并将对象传递给重定向的方法。

10.10.3

在Web应用中,操作会话(HttpSession)对象是十分普遍的,对此Spring MVC也提供了支持。主要是两个注解用来操作HttpSession对象,它们是@SessionAttribute
和@SessionAttributes。其中,@SessionAttribute应用于参数,它的作用是将 HttpSession中的属性读出,赋予控制器的参数;@SessionAttributes则
只能用于类的注解,它会将相关数据模型的属性保存都Session中。

10.10.4 给控制器增加通知

在Spring AOP中,可以通过通知来增强Bean的功能。同样地,Spring MVC也可以给控制器增加通知,于是在控制器方法的前后和异常发生时去执行不同的处理。
这里涉及4个注解,它们是@ControllerAdvice、@InitBinder、@ExceptionHandler和@ModelAttribute。这里需要注意的是它们的作用和执行顺序。

  • @ControllerAdvice:定义一个控制器的通知类,允许定义一些相关增强控制器的各类通知和限定增强那些控制器功能等。
  • @InitBinder:定义控制器参数绑定规则,如转换规则、格式化等,它会在参数转换之前执行。
  • @ExceptionHandler:定义控制器发生异常后的操作。
  • @ModelAndAttribute:可以在控制器方法执行前,对数据模型进行操作。

第十一章:构建Rest风格网站

REST按其英文名称(Representational State Transfer)可翻译为表现层状态转换。首先需要有资源才能表现,所以第一个名词是“资源”。有了资源也需要根据
合适的形式表现资源,这就是第二个名词“表现层”。最后是资源可以被新增、修改、删除等,也就是第三个名词“状态转换”。

11.2.4 渲染结果

在@RequestMapping、GetMapping等注解中还存在consumes和produces两个属性。其中consumes代表的是限制该方法接收什么类型的请求体(Body),produces
代表的是限定返回的媒体类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。

11.2.5 处理HTTP状态码、异常和响应头

Spring提供了实体封装类ResponseEntity和注解@ResponseStatus。ResponseEntity可以有效封装错误消息和状态码,通过@ResponseStatus可以配置指定的
响应码给客户端。

第十三章:学点Spring其他的技术

13.4 WebSocket应用

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器和服务器全双工通信 — 允许服务器主动发送信息给客户端,这样就可以实现从客户端发送消息到服务器,
而服务器又可以转发消息到客户端,这样就能够实现客户端之间的交互。对于WebSocket的开发,Spring也提供了良好的支持。目前很多浏览器已经实现了WebSocket协议,
但是依旧存在很多浏览器没有实现该协议,为了兼容那些没有实现该协议的浏览器,往往还需要通过STOMP协议来完成这些兼容。

13.4.2 使用STOMP

为了使得WebSocket的应用能够兼容那些不支持的浏览器,可以使用STOMP协议进行处理。首先需要在配置文件中假如注解@EnableWebSocketMessageBroker,
这个注解将会启动WebSocket下的子协议STOMP。为了配置这个协议,可以实现Spring提供给接口WebSocketMessageBrokerConfiguration。为了更为简单,
Spring还提供了这个接口的空实现的抽象类AbstractWebSocketMessageBrokerConfigurer,通过覆盖它所定义的方法即可。

第十四章:Spring5新框架 — WebFlux

14.1.1 响应式编程的宣言

对于响应式框架,是基于响应式宣言的理念所产生的编程方式。响应式宣言分为4大理念。

  • 灵敏的:就是可以快速响应,只要有任何可能,系统都能够尽快地做出响应。
  • 可恢复的:系统在运行中可能出现问题,但是能够有很大的容错机制和修复机制保持响应性。
  • 可伸缩的:在任何负载下,响应式变成都可以根据自身压力变化,请求少时,通过减少资源释放服务器的压力。负载大时,能够通过扩展算法和软硬件的方式扩展服务能力。
  • 消息驱动的:响应式变成存在异步消息机制,事件之间的协作是通过消息进行连接的。

14.1.3 Spring WebFlux的概述

在Spring WebFlux中,存在两种开发方式,一种是类似于SpringMVC的模式,另一种则是函数功能性的编程。

数据流
Reactor提供的Flux和Mono,它们都是封装数据流的类。其中Flux是存放0N个数据流序列,响应式框架会一个接一个地将它们发送到客户端;而对于Mono则是存放01
个数据流序列,这就是它们之间的区别,而它们是可以互相转换的。

背压
对于客户端,有时候响应能力距离服务端有很大的差距,如果在很短的时间内服务端将大量的数据流传输给客户端,那么客户端就可能被压垮。为了处理这个问题,一般会
考虑使用响应式拉取,也就是将服务端的数据流划分为多个序列,一次仅发送一个数据流序列给客户端,当客户端处理完这个序列后,再给客户端发送消息,然后再拉取
第二个序列进行处理,以此类推,直至Flux中的0~N个数据流被完全处理,这样客户端就可以根据自己响应的速度来获取数据流。

第十六章:部署、测试和监控

16.4.4 自定义端点

除了使用Actuator默认给予的端点外,还可以自定义端点来满足自定义监控的要求。在Actuator中加入端点只需要加入注解@Endpoint即可,这个注解会同时提供
JMX监控和Web监控。如果只想提供JMX监控,可以使用注解@JmxEndpoint;如果只想提供Web监控,可以使用注解@WebEndpoint。正如上述内容所示,Actuator
还会存在默认的端点,也可以使用@WebEndpointExtension或者@EndpointJmxExtension对已有的端点进行扩展。

第十七章:分布式开发 — SpringCloud

17.4 路由网关 — Zuul

在传统的网站中,我们还会引入Nginx、F5的网关功能。网关的功能对于分布式网站是十分重要的,首先它可以将请求路由到真实的服务器上,进而保护真实服务器的IP地址,
避免直接攻击真实服务器;其次,它也可以作为一种负载均衡的手段,使得请求按照一定的算法平摊到多个节点上,减缓单点的压力;最后,它还提供了过滤器,过滤器
的使用可以判定请求是否为有效请求,一旦判定失败,就可以即将请求阻止,避免发送到真实的服务器,这样就能降低真实服务器的压力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值