第 1 章 – 微服务基础知识
在进行 SpringCloud 的具体内容介绍之前,我们先通过本章学习一些关于微服务架构以及 SpringCloud 的基础知识。对 SpringCloud 能够解决的具体问题有一个大致的了解,以帮助我们更好地理解后续章节对各个组件的介绍。
学习目标:
- 了解分布式系统
- 了解什么是微服务架构
- 为什么选择 Spring Cloud
随着业务规模和系统复杂度的提升,很多系统会历经从单一架构到垂直架构,再到分布式架构的技术发展过程。
单体系统
在以往传统的企业系统架构中,我们针对一个复杂的业务需求通常使用对象或业务类型来构建一个单体项目。在项目中我们通常将需求分为三个主要部分:数据库、服务端处理、前端展现。在业务发展初期,由于所有的业务逻辑在一个应用中,开发、测试、部署都还比较容易且方便。
但是由于单体系统部署在一个进程内,功能之间是紧密耦合的, 往往我们修改了一个很小的功能,部署上线会影响其他功能的运行。
并且,单体应用中的这些功能模块的使用场景、并发量、消耗的资源类型都各有不同,对于资源的利用又互相影响,这样使得我们对各个业务模块的系统容量很难给出较为准确的评估。
所以,单体系统在初期虽然可以非常方便地进行开发和使用,但是随着系统的发展,维护成本会变得越来越大,且难以控制。
面对大流量高并发的用户访问,以及随之产生的海量数据处理等诸多挑战下,如何能为用户提供稳定可靠的服务,成为目前很多互联网大公司面临的技术问题。比如,常见的高并发场景有:
- 购物节
- 春运购票
- 秒杀系统
- 抖音
购物节的支付系统要想要在高并发的场景下实现五个 9(99.999%)的高可用性,保证支付率,还要保证秒杀场景下单位时间内成交的订单数更多,仅靠单一架构是不能做到的。
如果采用集群的垂直架构,随着业务的发展和系统复杂度的提生,要会出现越来越多的子项目,并且子项目之间功能存在重叠, 维护和部署也变更复杂,很难方便的扩展。
因此越来越多的公司采用分布式架构
分布式架构
将一个系统横向分成若干子系统或服务,实现服务性能的动态扩容。
这不但大幅提高服务处理能力, 且降低单一程序的开发维护以及部署难度。
从整体来看系统复杂度和部署难度是增加了, 但是可以通过 CI/CD 即持续集成和持续部署手段将繁杂的测试部署等环节尽可能自动化.
使用分布式服务作为软件体系结构的最早记录可追溯到二十世纪 80 年代初。
SOA 架构
SOA 首先在 90 年代中期得名,当时一家名为 Gartner Group 的公司认识到了这个软件架构的新趋势,并在全球推广。通过这样做,他们设法大大加快了这种架构模式的采用和进一步发展。
SOA(全称:Service Oriented Architecture),中文意思为 “面向服务的架构”,你可以将它理解为一个架构模型或者一种设计方法,而并不是服务解决方案。其中包含多个服务, 服务之间通过相互依赖或者通过通信机制,来完成相互通信的,最终提供一系列的功能。一个服务通常以独立的形式存在与操作系统进程中。各个服务之间通过网络调用 。
SOA 通常使用 ESB(企业总线)来连接各个服务节点。各个服务之间,只需要和 ESB 进行通信,这个时候,各个应用之间的交互就会变得更加的清晰,业务架构/逻辑等,也会变得很清楚。原本杂乱没有规划的系统,梳理成了一个有规划可治理的系统。
微服务架构
“微服务”一词源于 Martin Fowler 的名为 Microservices 的博文.
简单地说,微服务是系统架构上的一种设计风格,可以认为 SOA 是微服务的超集。微服务架构重点强调的一个是"业务需要彻底的组件化和服务化",原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用称为微服务,微服务之间通过基于 HTTP 的 RESTful API 进行通信协作。每个服务都维护着自身的数据存储、业务开发、自动化测试案例以及独立部署机制。由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。
微服务和 SOA 的区别
-
微服务去中心化,去掉 ESB 企业总线。微服务不再强调传统 SOA 架构里面比较重的 ESB 企业服务总线,同时 SOA 的思想进入到单个业务系统内部实现真正的组件化。
-
Docker 容器技术的出现,为微服务提供了更便利的条件,比如更小的部署单元,每个服务可以通过类似 Node 或者 SpringBoot 等技术跑在自己的进程中。
-
SOA 注重的是系统集成方面,而微服务关注的是完全分离。
由于微服务是独立部署的,我们可以更准确地为每个服务评估性能容量,通过配合服务间的协作流程也可以更容易地发现系统的瓶颈位置,以及给出较为准确的系统级性能容量评估。
- 使用微服务架构的厂商
- 淘宝
- 京东
- 抖音
- … …
RPC(remote procedure call)
整个应用分散成多个服务使得整个系统变得更为复杂。我们需要在分布式开发中引入额外的技术,以解决服务之间交互和分布式部署导致的问题。
RPC(远程过程调用),即在本地调用远程机器的函数或者对象方法,使实际的体验和调用本地函数或者对象方法无异。
RPC 也是一种技术思想,HTTP 和 WebService 就是 RPC 思想的一种很好的体现方式,但 HTTP 已经满足不了企业内外部日益复杂的信息交互。因此许多优秀的 RPC 框架应运而生,比如著名的 Dubbo ,封装了一些像负载均衡、熔断降级、服务注册发现等面向对象的高级特性。
如何实施微服务
在实施微服务之前,我们必须要知道,微服务虽然有非常多吸引人的优点,但是也因为服务的拆分引发了诸多原本在单体应用中没有的问题。
-
运维的新挑战:在微服务架构中,运维人员需要维护的进程数量会大大增加。我们需要运维人员有更多的技能来应对这样的挑战,运维过程需要更多的自动化,这就要求运维人员具备一定的开发能力来编排运维过程并让它们能自动运行起来。
-
接口的一致性:虽然我们拆分了服务,但是业务逻辑上的依赖并不会消除,只是从单体应用中的代码依赖变为了服务间的通信依赖。我们需要更完善的接口和版本管理,或是严格地遵循开闭原则。
-
分布式的复杂性:由于拆分后的各个微服务都是独立部署并运行在各自的进程内,它们只能通过通信来进行协作,所以分布式环境的问题都将是微服务架构系统设计时需要考虑的重要因素,比如网络延迟、分布式事务、异步消息等。
-
尽管微服务架构有很多缺点和问题,但是其实现的敏捷开发和自动化部署等优点依然被广大优秀架构师和开发者所青睐.微服务架构并没有一个标准或正式的定义,
Martin Fowler 在 Microservices—文中,提炼出了微服务架构的九大特性,用于指导大家设计架构。
1. 服务组件化
在微服务架构中,需要我们对服务进行组件化分解。服务,是一种进程外的组件,它通过 HTTP 等通信协议进行协作,而不是像传统组件那样以嵌入的方式协同工作。每一个服务都独立开发、部署,可以有效避免一个服务的修改引起整个系统的重新部署。
2. 按业务组织团队
在实施微服务架构时,需要采用不同的团队分割方法。由于每一个微服务都是针对特定业务的宽栈或是全栈实现,既要负责数据的持久化存储,又要负责用户的接口定义等各种跨专业领域的职能。因此,面对大型项目的时候,对于微服务团队的拆分更加建议按业务线的方式进行拆分,一方面可以有效减少服务内部修改所产生的内耗;另一方面,团队边界可以变得更为清晰.
康威法则: 一个组织的结构应该反映其沟通结构。
3. 做“产品”的态度
在实施微服务架构的团队中,每个小团队都应该以做产品的方式,对其产品的整个生命周期负责。持续关注服务的运作情况,并不断分析以帮助用户来改善业务功能。
4. 智能端点与哑管道
在微服务架构中,组件间的通信模式发生了改变,若仅仅将原本在进程内的方法调用改成 RPC 方式的调用,会导致微服务之间产生烦琐的通信,使得系统表现更为糟糕,所以,我们需要更粗粒度的通信协议。
Martin Flower 将微服务架构的服务通信理念称为“Smart endpoints and dumb pipes”, 简单翻译为“聪明的终端,愚蠢的管道”,大意是指强服务个体和弱通信。
在微服务架构中,通常会使用以下两种服务调用方式:
- 使用 HTTP 的 RESTful API 或轻量级的消息发送协议
- 通过在轻量级消息总线上传递消息,类似 RabbitMQ 等一些提供可靠异步交换的中间件。
在极度强调性能的情况下,有些团队会使用二进制的消息发送协议,例如 protobuf 即使是这样,这些系统仍然会呈现出“智能端点和哑管道”的特点,这是为了在易读性与高效性之间取得平衡。当然大多数 Web 应用或企业系统并不需要在这两者间做出选择,能够获得易读性已经是一个极大的胜利了。
5. 去中心化治理
在实施微服务架构时,通过采用轻量级的契约定义接口,使得我们对于服务本身的具体技术平台不再那么敏感,这样整个微服务架构系统中的各个组件就能针对其不同的业务特点选择不同的技术平台.
6. 去中心化管理数据
我们在实施微服务架构时,都希望让每一个服务来管理其自有的数据库,这就是数据管理的去中心化。
由于数据存储于不同的数据库实例中后,数据一致性也成为微服务架构中亟待解决的问题之一。(分布式锁,分布式事务)
7. 基础设施自动化
近年来云计算服务与容器化技术的不断成熟,在微服务架构中,务必从一开始就构建起“持续交付”平台来支撑整个实施过程:
- 自动化测试:每次部署前的强心剂,尽可能地获得对正在运行的软件的信心。
- 自动化部署:解放烦琐枯燥的重复操作以及对多环境的配置管理。
8. 容错设计
微服务架构中,由于服务都运行在独立的进程中,所以存在部分服务出现故障,而其他服务正常运行的情况。由于服务之间存在调用链,因此在微服务架构中,快速检测出故障源并尽可能地自动恢复服务是必须被设计和考虑的。
通常,我们都希望在每个服务中实现监控和日志记录的组件,比如服务状态、断路器状态、吞吐量、网络延迟等关键数据的仪表盘等。
9. 演进式设计
在很多情况下,架构师都会以演进的方式进行系统的构建。
-
在初期,以单体系统的方式来设计和实施,一方面系统体量初期并不会很大,构建和维护成本都不高,此时还不需要微服务架构。
-
随着系统的发展或者业务的需要,架构师会将一些经常变动或是有一定时间效应的内容进行微服务处理,并逐渐将原来在单体系统中多变的模块逐步拆分出来,而稳定不太变化的模块就形成一个核心微服务存在于整个架构之中。
Spring Cloud
SpringCloud 的出现,可以说是对微服务架构的巨大支持和强有力的技术后盾,SpringCloud 是一个解决微服务架构实施的综合性解决框架的有序集合,利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。
SpringCloud 核心部件:
近几年人们对于微服务架构的热情非常高,无数的架构师和开发者在实际项目中实践该设计理念并为此付出了诸多努力,同时也分享了他们在微服务架构中针对不同应用场景出现的各种问题的各种解决方案和开源框架,其中也不乏国内互联网企业的杰出贡献。
- 服务治理:阿里巴巴开源的 Spring Cloud Alibaba Nacos、Netflix 的 Eureka、Apache 的 Consul 等。
- 分布式配置管理:百度的 Disconf、SpringCloud 的 Config、阿里巴巴开源的 Spring Cloud Alibaba Nacos 等。
- 批量任务:当当网的 Elastic-Job、Linkedln 的 Azkaban、SpringCloud 的 Task 等。
- 服务跟踪:京东的 Hydra、SpringCloud 的 Sleuth、Twitter 的 Zipkin 等。
早期 Netflix 和现在的 Alibaba 都是非常重要的 SpringCloud 的贡献者,他们都是微服务架构的先行者,他们的开源框架和解决方案都是我们在实施微服务架构时的参考。
Spring Cloud Netflix
Spring Cloud Alibaba
上面列举了一些在实施微服务架构初期,就需要被我们考虑进去的问题,以及针对这些问题的开源解决方案。可以看到国内、国外的技术公司都在贡献着他们的智慧。我们搜索微服务架构的实施方案时会发现,几乎大部分的分享主要以理论或是一个粗轮廓框架为主,整合了来自不同公司或组织的诸多开源框架,并加入针对自身业务的一些优化,所以找不到一个完全相同的架构方案。
Spring Cloud 包含了多个子项目(针对分布式系统中涉及的多个不同开源产品,还可能会新增),挑选部分项目,如下所述。
-
Spring Cloud Config:配置管理工具,支持使用 Git 存储配置内容,可以使用它实现应用配置的外部化存储,并支持客户端配置信息刷新、加密/解密配置内容等。
-
Spring Cloud Netflix:核心组件,对多个 Netflix OSS 开源套件进行整合。
- Eureka:服务治理组件,包含服务注册中心、服务注册与发现机制的实现。
- Hystrix:容错管理组件,实现断路器模式,帮助服务依赖中出现的延迟和为故障提供强大的容错能力。
- Ribbon:客户端负载均衡的服务调用组件。
- Feign:基于 Ribbon 和 Hystrix 的声明式服务调用组件。
- Zuul:网关组件,提供智能路由、访问过滤等功能
-
Spring Cloud Alibaba: 核心组件,对多个 Alibaba 开源套件进行整合.
- 流量控制和服务降级: Alibaba Sentinel 的流量控制、断路和系统自适应保护
- 服务注册与发现:实例注册到阿里巴巴的 Nacos,通过负载均衡器 Ribbon,客户端可以通过 Spring 管理的 bean 发现实例。
- 分布式配置:使用阿里巴巴 Nacos 作为数据存储
- 事件驱动:构建与 Spring Cloud Stream RocketMQ Binder 连接的高度可扩展的事件驱动微服务
-
Spring Cloud Bus:事件、消息总线,用于传播集群中的状态变化或事件,以触发后续的处理,比如用来动态刷新配置等
-
Spring Cloud Cluster:针对 ZooKeeper、Redis、Hazelcast、Consul 的选举算法和通用状态模式的实现。
-
Spring Cloud Stream:通过 Redis、RabbitMQ 或者 Kafka 实现的消费微服务,可以通过简单的声明式模型来发送和接收消息。
- Spring Cloud Security:安全工具包,提供在 Zuul 代理中对 OAuth2 客户端请求的中继器。
- Spring Cloud Sleuth: SpringCloud 应用的分布式跟踪实现,可以完美整合 Zipkin
- Spring Cloud ZooKeeper:基于 ZooKeeper 的服务发现与配置管理组件。
- Spring Cloud Starters:SpringCloud 的基础组件,它是基于 SpringBoot 风格项目的基础依赖模块。
Spring Cloud 版本说明
当我们通过搜索引擎查找一些 SpringCloud 的文章或示例时,往往可以在依赖中看到很多不同的版本名字,比如 Angel.SR6、Brixton.SR5 等,为什么 SpringCloud 没有像其他 Spring 的项目使用类似 l.x.x 的版本命名规则呢?这些版本之间又有什么区别呢?在学习之初,非常有必要弄清楚这些版本的意义和内容,这样才能在我们使用 SpringCloud 时,指导我们选择更为合适的版本进行架构与开发。
版本名与版本号
由于 SpringCloud 不像 Spring 社区其他一些项目那样相对独立,它是一个拥有诸多子项目的大型综合项目,可以说是对微服务架构解决方案的综合套件组合,其包含的各个子项目也都独立进行着内容更新与迭代,各自都维护着自己的发布版本号。因此每一个 Spring Cloud 的版本都会包含多个不同版本的子项目,为了管理每个版本的子项目清单,避免 SpringCloud 的版本号与其子项目的版本号相混
淆,没有采用版本号的方式,而是通过命名的方式。
这些版本的名字采用了伦敦地铁站的名字,根据字母表的顺序来对应版本时间顺序,比如最早的 Release 版本为 Angel,第二个 Release 版本为 Brixton 经过上面的解释,不难猜出,之前所提到的 Angel.SR6、Brixton.SR5 中的 SR6、SR5 就是版本号了。
当一个版本的 SpringCloud 项目的发布内容积累到临界点或者一个严重 bug 解决可用后,就会发布一个“servicereleases”版本,简称 SRX 版本,其中 X 是一个递增的数字,所以 Brixton.SR5 就是 Brixton 的第 5 个 Release 版本。
SpringCloud 与 SpringBoot 的版本兼容关系如下:
Release Train | Boot Version |
---|---|
2021.0.x aka Jubilee | 2.6.x |
2020.0.x aka Ilford | 2.4.x, 2.5.x (Starting with 2020.0.3) |
Hoxton | 2.2.x, 2.3.x (Starting with SR5) |
Greenwich | 2.1.x |
Finchley | 2.0.x |
Edgware | 1.5.x |
Dalston | 1.5.x |
注意:在本教程,主要以 Hoxton.SR10 版本进行案例演示.因此对应的 SpringBoot 版本是 2.2.x ~ 2.3.x 版本.
活动手册
我们在构建 SpringBoot 应用的时候,总是需要一整套的符合 MVC 规范的简单模板文件,为了避免重复性操作,我们可以使用一些工具类帮我们完成这部分的工作.比如说 Intellij IDEA 的一款优秀插件: EasyCode。
EasyCode 是基于 IntelliJ IDEA 开发的代码生成插件,支持自定义任意模板(Java,html,js,xml)。只要是与数据库相关的代码都可以通过自定义模板来生成。支持数据库类型与 java 类型映射关系配置。支持同时生成生成多张表的代码。每张表有独立的配置信息。完全的个性化定义,规则由你设置。
活动 1.1 使用 EasyCode 插件生成辅助代码
创建项目- 推荐使用 Spring Initializr 创建项目
-
使用https://start.aliyun.com/ 作为启动页
-
建议使用 JDK11 或 JDK17
-
依赖:
-
spring-boot-starter-parent 2.3.12.RELEASE
-
springboot-starter-web – 相关
-
springboot-starter-jdbc
-
spring-data-commons 2.3.9.RELEASE
-
mybatis-spring-boot-starter 2.1.4
-
mysql-connector-java (5.1.x)
-
spring-boot-starter-actuator
-
lombok optional
-
spring-boot-configuration-processor optional
-
spring-boot-devtool optional
-
步骤 1. 安装 EasyCode 插件
步骤 2. 配置 EasyCode 插件
步骤 3. 配置数据库连接
按照活动手册要求创建数据库, 然后Views -> Tool Windows -> Database
步骤 4. 配置模板
settings -> Other Settings -> EasyCode -> templates
如果使用 lombok,需要在 entity 类模板中添加
@Data
注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
##使用全局变量实现默认包导入 $!{autoImport.vm} import java.io.Serializable; import lombok.Data; ##使用宏定义实现类注释信息 #tableComment("实体类") @Data public class $!{tableInfo.name} implements Serializable { private static final long serialVersionUID = $!tool.serial(); #foreach($column in $tableInfo.fullColumn) #if({column.comment})/** * ${column.comment} */#end private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; #end |
dao 接口类模板示例
queryAllByLimit
代码需要修改才能使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public interface $!{tableName} { /** * 通过ID查询单条数据 * @param $!pk.name 主键 * @return 实例对象 */ $!{tableInfo.name} queryById($!pk.shortType $!pk.name); /** * 查询指定行数据 * @param $!tool.firstLowerCase($!{tableInfo.name}) 查询条件 * @param pageable 分页对象 * @return 对象列表 */ List<$!{tableInfo.name}> queryAllByLimit( @Param("entity") $!{tableInfo.name} $!tool.firstLowerCase($!{tableInfo.name}), @Param("pageable") Pageable pageable ); |
mapper.xml
模板示例
mapper.xml
文件保存路径需要调整与 SpringBoot 默认的一致
1 2 3 4 5 6 |
##引入mybatis支持 $!{mybatisSupport.vm} ##设置保存名称与保存位置 $!callback.setFileName($tool.append($!{tableInfo.name}, "Dao.xml")) $!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mappers")) |
mapper.xml
模板示例
queryAllByLimit
的查询需要修改才能使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<!--查询单个--> <select id="queryById" resultMap="$!{tableInfo.name}Map"> select #allSqlColumn() from $!tableInfo.obj.name where $!pk.obj.name = #{$!pk.name} </select> <!--查询指定行数据--> <select id="queryAllByLimit" resultMap="$!{tableInfo.name}Map"> select #allSqlColumn() from $!tableInfo.obj.name <where> #foreach($column in $tableInfo.fullColumn) <if test="entity.$!column.name != null #if($column.type.equals("java.lang.String")) and entity.$!column.name != '' #end "> and $!column.obj.name = #{entity.$!column.name} </if> #end </where> <if test="pageable.sort != null and pageable.sort.orders.size > 0"> order by <foreach collection="pageable.sort.orders" item="order" separator=","> ${order.property} ${order.direction} </foreach> </if> limit #{pageable.offset}, #{pageable.pageSize} </select> |
步骤 5. 生成代码
application.properties 需要修改mapper.xml的生成路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 应用名称 spring.application.name=EasyCodeDemo # 数据库驱动: spring.datasource.driver-class-name=com.mysql.jdbc.Driver # 数据源名称 spring.datasource.name=MySQLDataSource # 数据库连接地址 spring.datasource.url=jdbc:mysql://localhost:3306/course?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false # 数据库用户名&密码: spring.datasource.username=root spring.datasource.password=niit1234 #下面这些内容是为了让MyBatis映射 #指定Mybatis的Mapper文件 - EasyCode自动生成的包为mapper, 需修改 mybatis.mapper-locations=classpath:mappers/*xml #指定Mybatis的实体目录 mybatis.type-aliases-package=com.example.easycodedemo.mybatis.entity # debug logging.level.com.example.easycodedemo=debug spring.jpa.show-sql=true |
可以选择多表, 选择生成代码
指定生成规则, 点击 OK 进行生成
指定 Mapper 的包扫描路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.example.easycodedemo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.easycodedemo.dao") public class EasyCodeDemoApplication { public static void main(String[] args) { SpringApplication.run(EasyCodeDemoApplication.class, args); } } |
测试:
- 对于 get 请求可以直接使用浏览器窗口进行测试(只支持 get)
- 或者编写页面使用 ajax 进行测试
- 或者 idea 的插件 (方便)
- HTTP Client(Builtin)
- RestfulTool(MarketPlace 免费)
- Restful Fast Request(收费)
- 另外还可以使用专用软件进行测试 (功能强大)
- curl
- postman
- apifox
- apipost
这里使用 RestfulTool 进行测试: body 设置{}
表示无条件分页查询
分页查询报错的问题解决
测试http://localhost:8080/course/
接口收到报错如下:
1 2 3 4 5 |
[Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for class org.springframework.data.domain.PageRequest] with root cause java.lang.NoSuchMethodException: org.springframework.data.domain.PageRequest.<init>() |
新建config
包, 并创建一个自定义参数解析器PageRequestHandlerMethodArgumentResolver
, 让它也能解析Pageable
的子类 PageRequest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Component public class PageRequestHandlerMethodArgumentResolver extends PageableHandlerMethodArgumentResolver { /** * {@link PageableHandlerMethodArgumentResolver} SpringData 提供的只能解析 {@link Pageable} 类型的 * 这里让它也能解析它的子类 {@link PageRequest} * * @param parameter * @return */ @Override public boolean supportsParameter(MethodParameter parameter) { return Pageable.class.isAssignableFrom(parameter.getParameterType()); } } |
接着创建WebConfig
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private PageRequestHandlerMethodArgumentResolver pageRequestHandlerMethodArgumentResolver; /** * 添加自定义参数解析器 * * @param argumentResolvers */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(pageRequestHandlerMethodArgumentResolver); } } |
分页和排序支持:
http://localhost:8080/course?size=2&page=0&sort=cid,desc&sort=cname,asc
表示:
- 页容量为2, 显示第1页的数据
- 二次排序: 先按cid倒序, 再按cname正序
小问题:
Spring Cloud 为以下哪些操作提供了一种简单的开发方式?
- A. 服务治理
- B. 智能路由
- C. 微代理
- D. 控制总线
谢谢
Views: 4