服务端开发(7) REST服务、微服务开发与部署
1. 一个 Web App 的开发和快速反馈
华为云软件开发生产线 CodeArts
- 集合业界先进理念,华为30年研发经验,可操作可落地的端到端一站式开发方法论和工具链。
- 学习链接: https://support.huaweicloud.com/devcloud/index.html
- 集华为研发实践、前沿研发理念、先进研发工具于一体,使能软件企业/开发者简单高效地向最终用户交付有价值的软件。
2. 开发模式
前、后端不分离的开发模式
前后端分离的开发模式
3. 单体应用程序
- 数据库的表对所有模块可见
- 一个人的修改整个应用都要重新构建、测试、部署
- 整体复制分布式部署,不能拆分按需部署
4. 微服务架构模式的特征
- 应用程序分解为具有明确定义了职责范围的细粒度组件
- 完全独立部署,独立测试,并可复用
- 使用轻量级通信协议,HTTP 和 JSON,松耦合
- 服务实现可使用多种编程语言和技术
- 将大型团队划分成多个小型开发团队,每个团队只负责他们各自的服务
5. Spring Boot 和 Spring Cloud
- Spring Boot 提供了基于 Java 的、面向 REST 的微服务框架
- Spring Cloud 使实施和部署微服务到私有云或公有云变得更加简单
5.1 Spring Boot
- 简化 Spring Web 开发
- Spring Boot Starter
- 自动管理依赖、版本号
- 自动配置
- 根据类路径加载的类自动创建需要的Bean
- 如: DataSource、JdbcTemplate、视图解析器等
Actuator
- /autoconfig 使用了哪些自动配置(positiveMatches)
- /beans,包含bean依赖关系
Spring initializer: 生成初始框架代码
6. Rest原则
- Representational State Transfer,表现层状态转移
- 资源(Resources),就是网络上的一个实体,标识: URI
- 表现层(Representation): json、xml、html、pdf、excel
- 状态转移(State Transfer): 服务端—客户端
- HTTP协议的四个操作方式的动词: GET、POST、PUT、DELETE
- CRUD: Create、Read、Update、Delete
- 如果一个架构符合REST原则,就称它为RESTful架构。
7. 客户端与服务的交互
7.1 请求报文
请求头与请求体
请求头: 请求头由 key/value 对组成,每行为一对,key 和 value 之间通过冒号(:)分割。请求头的作用主要用于通知服务端有关于客户端的请求信息。
- User-Agent: 生成请求的浏览器类型
- Accept: 客户端可识别的响应内容类型列表
- 星号 $\ast$ 用于按范围将类型分组
- $\ast / \ast$表示可接受全部类型
- $\text{type}/\ast$ 表示可接受 type 类型的所有子类型
- Accept-Language: 客户端可接受的自然语言
- Accept-Encoding: 客户端可接受的编码压缩格式
- Accept-Charset: 可接受的字符集
- Host: 请求的主机名,允许多个域名绑定同一 IP 地址
- connection: 连接方式(close 或 keepalive)
- Cookie: 存储在客户端的扩展字段
- Content-Type:标识请求内容的类型
- Content-Length:标识请求内容的长度
请求体: 请求体主要用于 POST 请求,与 POST 请求方法配套的请求头一般有 Content-Type 和 Content-Length
7.2 响应报文
响应头与响应体
状态行:由 HTTP 协议版本、状态码、状态码描述三部分构成,它们之间由空格隔开
状态码:由 3 位数字组成,第一位标识响应的类型,常用的 5 大类状态码如下:
- 1xx:表示服务器已接收了客户端的请求,客户端可以继续发送请求
- 2xx:表示服务器已成功接收到请求并进行处理
- 3xx:表示服务器要求客户端重定向
- 4xx:表示客户端的请求有非法内容
- 5xx:标识服务器未能正常处理客户端的请求而出现意外错误
响应头:
- Location:服务器返回给客户端,用于重定向到新的位置
- Server:包含服务器用来处理请求的软件信息及版本信息Vary:标识不可缓存的请求头列表
- Connection: 连接方式
- close 是告诉服务端,断开连接,不用等待后续的请求了
- keep-alive 则是告诉服务端,在完成本次请求的响应后,保持连接
- Keep-Alive: 300,期望服务端保持连接多长时间(秒)
响应内容:服务端返回给请求端的文本信息。
7.3 客户端表述的两种方式
内容协商(Content negotiation)
ContentNegotiatingViewResolver
是要创建的bean,基于内容协商生成表述,判断的依据有请求头的 Accept,URL请求路径加扩展名(优先)- 然后会转向具体的视图解析器生成不同的视图表述
ContentNegotiationManager
(配置的作用)- 通过 setter 注入到
ContentNegotiatingViewResolver
中 - 创建这个 Bean 的方式是继承自
WebMvcConfigerAdapter
(基于spring mvc) - 覆盖方法
configureContentNegotiation
,配置缺省内容类型等。
- 通过 setter 注入到
消息转换器(Message conversion)
- 使用注解
@ResponseBody
或类级@RestController
,作用:指定使用消息转换器 - 没有 model 和视图,控制器产生数据,然后消息转换器转换数据之后的资源表述
- spring 自动注册一些消息转换器(
HttpMethodConverter
),不过类路径下要有对应转换能力的库,如:Jackson Json processor、JAXB库 - 请求传入,
@RequestBody
以及HttpMethodConverter
7.4 提供资源以外的其它内容
@ResponseStatus(HttpStatus.CREATED)
指定返回的状态码- 控制器方法返回
ResponseEntity
对象,指定业务对象(负载)、状态码、响应头- 不用使用
@ResponseBody
注解
- 不用使用
- 异常处理器,
@ExceptionHandler
(异常类型),加在方法上 - 指定响应头信息,通过返回
ResponseEntity
对象的方式HttpHeaders
类型- 注意与发出请求时的类型
MultiValueMap
区别
- 注意与发出请求时的类型
setLocation
8. Rest客户端
new RestTemplats()
getForObject()
, 指定返回类型,自动转换getForEntity()
,返回ResponseEntity
, 有头部信息,getBody()
可以转换put()
,传递的对象存在转换问题,String 转成 test/plain,MultiValueMap 转成 x-www-form-urlncoded,对象可能转成json,要看 classpass 类路径下有无库delete()
,删除一个资源,一般提供资源路径即可postForObject()
/postForEntity()
/postForLocation()
- 因为需要返回值
postForLocation
,只需要路径,不需要body,路径信息来源头部 Location 信息
exchange()
, 可指定请求头信息MultiValueMap headers;
HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);
ResponseEntity<Spitter> response = rest.exchange()
例子代码
@SpringBootApplication
- 配置类
@Configuration
@ComponentScan
- 配置类
@RestController
@Controller
- 请求响应,JSON编解码(序列化)
mvn spring-boot:run
- 健康检查:http://localhost:8080/actuator/health
9. 现实和挑战
- 程序规模越来越大、越来越复杂
- 客户期望快速频繁交付
- 性能和可伸缩性
- 弹性,应用程序中某个部分的故障或问题不应该导致整个应用程序崩溃
- 小型的、简单的和解耦的服务 = 可伸缩的、有弹性的和灵活的应用程序
9.1 云计算平台
- 基础设施即服务(Infrastructure as a Service , IaaS)
- 平台即服务(Platform as a Service, PaaS)
- 软件即服务(Software as a Service, SaaS)
- 函数即服务(Functions as a Service, FaaS),将代码块以“无服务器”(serverless)的形式部署,无须管理任何服务器基础设施
- 容器即服务(Container as a Service, CaaS),如亚马逊ECS(Amazon’s Elastic Container Service)
9.2 微服务开发要考虑的问题
- 微服务划分,服务粒度、通信协议、接口设计、配置管理、使用事件解耦微服务
- 服务注册、发现和路由
- 弹性,负载均衡,断路器模式(熔断),容错
- 可伸缩
- 日志记录和跟踪
- 安全
- 构建和部署,基础设施即代码
9.3 Spring Cloud的工具集成
- spring cloud alibaba
- 数据配置,与 Nacos 集成
- 服务注册与发现,与 Nacos 集成
- Spring Cloud Loadbalancer
- Spring Cloud openfeign
- 限流、熔断,与 Sentinel 集成
- Spring Cloud gateway,网关服务
- Spring Cloud Stream,与 RabbitMQ、Kafka 集成
- Spring Cloud Sleuth,与日志聚合工具Papertrail、跟踪工具Zipkin集成
- Spring Cloud Security,与OAuth2集成
9.4 微服务划分
- 可以从数据模型入手,每个域的服务只能访问自己的表
- 刚开始粒度可以大一点,不要太细,由粗粒度重构到细粒度是比较容易的
- 设计是逐步演化的
9.5 接口设计
- 使用标准 HTTP 动词:GET、PUT、POST、DELETE,映射到 CRUD
- 使用 URI 来传达意图
- 请求和响应使用 JSON
- 使用 HTTP 状态码来传达结果
9.6 运维实践
- 都在源代码库中
- 指定 JAR 依赖的版本号
- 配置与源代码分开放
- 已构建的服务是不可变的,不能再被修改
- 微服务应该是无状态的
- 并发,通过启动更多的微服务实例横向扩展,多线程是纵向扩展