SpringCloud
概述
- Spring Cloud是一系列框架的有序集合。
- Spring Cloud的本质是在 Spring Boot 的基础上,增加了一堆微服务相关的规范,并对应用上下文 (Application Context )进行了功能增强。
- 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
优点 | 缺点 |
---|
通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降 | 微服务过多,服务治理成本高,不利于系统维护。 | 微服务遵循单一原则。微服务之间采用Restful等轻量协议传输。 | 分布式系统开发的技术成本高(容错、分布式事务等)。 |
注意
微服务之间传递参数时 @RequestBody @PathVariable 不能省略!
spring:
application:
name: eureka
RestTempalte
代码:
消费者代码:
package com.sms.controller;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/conStudent")
public class StudentController {
@Autowired
RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
public String serviceUri() {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("provider-student");
if (serviceInstances != null && serviceInstances.size() > 0) {
return serviceInstances.get(0).getUri() + "/student/";
}
return null;
}
@GetMapping("/{id}")
public RespEntity getStuInfo(@PathVariable("id") Integer id) {
System.out.println("获取一个学生信息");
return restTemplate.getForObject(serviceUri() + id,
RespEntity.class);
}
@GetMapping("/")
public RespEntity getAllStudent() {
System.out.println("获取所有学生信息");
return restTemplate.getForObject(serviceUri(),
RespEntity.class);
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println("添加学生");
System.out.println(student);
return restTemplate.postForObject(serviceUri(), student, RespEntity.class);
}
}
提供者代码:
package com.sms.controller;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
@RestController
@RequestMapping("/student")
public class StudentController {
@Value("${server.port}")
private Integer port;
@GetMapping("/{id}")
public RespEntity getStudent(@PathVariable("id") Integer id) {
if (id == 1) {
return new RespEntity(1, "ok"+port, new Student(1, "test1", 12));
}
return new RespEntity(2, "ok"+port, new Student(2, "test2", 11));
}
@GetMapping("/")
public RespEntity getAllStudent() {
return new RespEntity(2, "ok"+port, Arrays.asList(
new Student(1, "test1", 12),
new Student(2, "test2", 11),
new Student(3, "test3", 13)
));
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println(student);
return new RespEntity(200, "ok"+port, null);
}
}
Eureka
概述:
Eureka是Net?ix开发的服务发现框架,SpringCloud将它集成在自己的子项目spring-cloud-net?ix中, 实现SpringCloud的服务发现功能。
微服务注册中心
原理:注册中心可以说是微服务架构中的通讯录,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到注册中心,当服务需要调用其它服务时,就到注册中心找到服务的地址,进行调用。
常见的注册中心:
组件名 | 语言 | CAP | 一致性算法 | 对外暴露接口 |
---|
Eureka | Java | AP | 无 | HTTP | Consul | Go | CP | Raft | HTTP/DNS | Zookeeper | Java | CP | Paxos | 客户端 | Nacos | Java | AP | Raft | HTTP |
CAP:三进二
C:一致性;
A:可用性;
P:分区容错性
在微服务下,分区容错性是必须实现,其一致性和可用性二选一,为了优化用户体验,一般会优先实现可用性,保证服务是可用状态。
基本架构:
Eureka Server :提供服务注册和发现 ;
Eureka Client:
? Service Provider :服务提供方(将自身服务注册到Eureka ,从而使服务消费方能够找到 )
? Service Consumer : 服务消费方 (从Eureka获取注册服务列表,从而能够消费服务)
- Eureka Server提供服务发现的能力,各个微服务启动时,会通过Eureka Client向Eureka Server 进行注册自己的信息(例如网络信息),Eureka Server会存储该服务的信息;
- 微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒)以续约自己的信息。如果Eureka Server在一定时间内没有接收到某个微服务节点的心跳,Eureka Server将会注销该微服 务节点(默认90秒);
- 每个Eureka Server同时也是Eureka Client ,多个Eureka Server之间通过复制的方式完成服务注册表的同步;
- Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者
自我保护:
- 微服务第一次注册成功之后,每30秒会发送一次心跳将服务的实例信息注册到注册中心。通知 Eureka Server该实例仍然存在。
- 如果超过90秒没有发送更新,则服务器将从注册信息中将此服务移除。
- Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85% ,如果出现低于的情况,Eureka Server会 将当前的实例注册信息保护起来,同时提示这个警告。
- 保护模式主要用于一组客户端和Eureka Server 之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)
关闭自我保护功能: eureka.service.enableSelfPreservation=false
服务剔除:
lease-renewal-interval-in-seconds: 服务续约(renew)的间隔, 默认为30秒
lease-expiration-duration-in-seconds: 服务失效时间,默认值90秒
也就是说,默认情况下每隔30秒服务会向注册中心发送一次心跳, 证明自己还活着。如果超过90秒没有发送心跳,EurekaServer就会认为该服务宕机,会定时(eureka.server.eviction-interval-timer.in-ms设定的时间,默认60秒) 从服务列表中移除,这两个值在生产环境不要修改,默认即可。
服务续约:
在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求) 。告诉EurekaServer: “我还活着"。称为服务的续约(renew) ;
服务失效:
lease-expiration-duration-in-seconds: 服务失效时间,默认值90秒
代码
pom:
<!--eureka 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
yml:
服务端:
server:
port: 6061
spring:
application:
name: eureka
eureka:
instance:
hostname: localhost
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:6061/eureka/
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
客户端:
server:
port: 8081
spring:
application:
name: provider-student
eureka:
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:6061/eureka/
instance:
lease-renewal-interval-in-seconds: 1
lease-expiration-duration-in-seconds: 2
服务提供者:
package com.sms.controller;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
@RestController
@RequestMapping("/student")
public class StudentController {
@Value("${server.port}")
private Integer port;
@GetMapping("/{id}")
public RespEntity getStudent(@PathVariable("id") Integer id) {
if (id == 1) {
return new RespEntity(1, "ok"+port, new Student(1, "test1", 12));
}
return new RespEntity(2, "ok"+port, new Student(2, "test2", 11));
}
@GetMapping("/")
public RespEntity getAllStudent() {
return new RespEntity(2, "ok"+port, Arrays.asList(
new Student(1, "test1", 12),
new Student(2, "test2", 11),
new Student(3, "test3", 13)
));
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println(student);
return new RespEntity(200, "ok"+port, null);
}
}
服务消费者:
package com.sms.controller;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/conStudent")
public class StudentController {
@Autowired
RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
public String serviceUri() {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("provider-student");
if (serviceInstances != null && serviceInstances.size() > 0) {
return serviceInstances.get(0).getUri() + "/student/";
}
return null;
}
@GetMapping("/{id}")
public RespEntity getStuInfo(@PathVariable("id") Integer id) {
System.out.println("获取一个学生信息");
return restTemplate.getForObject(serviceUri() + id,
RespEntity.class);
}
@GetMapping("/")
public RespEntity getAllStudent() {
System.out.println("获取所有学生信息");
return restTemplate.getForObject(serviceUri(),
RespEntity.class);
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println("添加学生");
System.out.println(student);
return restTemplate.postForObject(serviceUri(), student, RespEntity.class);
}
}
Ribbon
概述:
Ribbon是 Net?ix发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。
在 SpringCloud 中,Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。
在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务
主要作用:
服务调用 | 负载均衡 |
---|
基于Ribbon实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助 RestTemplate 最终进行调用 | 当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址 |
负载均衡:
两种方式:
服务端 | 客户端 |
---|
先发送请求到负载均衡服务器或者软件,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;即在服务器端再进行负载均衡算法分配 | 客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均衡算法分配 |
负载均衡策略:
com.netflix.loadbalancer.IRule | 顶级接口 |
---|
com.netflix.loadbalancer.RoundRobinRule | 以轮询的方式进行负载均衡。 | com.netflix.loadbalancer.RandomRule | 随机策略 | com.netflix.loadbalancer.RetryRule | 重试策略。 | com.netflix.loadbalancer.WeightedResponseTimeRule | 权重策略。会计算每个服务的权 重,越高的被调用的可能性越大。 | com.netflix.loadbalancer.BestAvailableRule | 最佳策略。遍历所有的服务实例,过滤掉 故障实例,并返回请求数最小的实例返回。 | com.netflix.loadbalancer.AvailabilityFilteringRule | 可用过滤策略。过滤掉故障和请 求 |
代码:
@Configuration
public class RestTemplateConfiguration {
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RequestMapping("/consumerstudent")
public class ConsumerStudent {
@Autowired
RestTemplate restTemplate;
public String serviceUrl() {
return "http://provider-student/student/";
}
@GetMapping("/{id}")
public RespEntity getStuInfo(@PathVariable("id") Integer id) {
System.out.println("获取一个学生信息");
return restTemplate.getForObject(serviceUri() + id,
RespEntity.class);
}
}
OpenFeign
概述:
- Feign是Net?ix开发的声明式,模板化的HTTP客户端。
- Feign可帮助我们更加便捷,优雅的调用HTTP API。
- 在SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。
- SpringCloud对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka ,从而让Feign的使用更加方便。
负载均衡:
Feign中本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册RestTemplate 对象
超时控制:
默认Feign客户端只等待1秒钟,但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了 ,直接返回报错。
为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。
可以在ymI文件中开启配置
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
日志打印:
配置
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
logging:
level:
com.woniuxy.consumer.student.feignclient.StudentFeignClient: debug
代码:
客户端消费者:
pom
<!--Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
定义声明式接口:
package com.sms.FeignClient;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
@FeignClient("provider-student")
public interface IStudentFeignClient {
@GetMapping("/student/{id}")
RespEntity getStudent(@PathVariable("id") Integer id);
@GetMapping("/student/")
RespEntity getAllStudent();
@PostMapping("/student/")
RespEntity addStudent(@RequestBody Student student);
}
调用接口
package com.sms.controller;
import com.sms.FeignClient.IStudentFeignClient;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/feignstudent")
public class StudentFeignController {
@Autowired
IStudentFeignClient iStudentFeignClient;
@GetMapping("/{id}")
public RespEntity getStuInfo(@PathVariable("id") Integer id) {
System.out.println("获取一个学生信息");
return iStudentFeignClient.getStudent(id);
}
@GetMapping("/")
public RespEntity getAllStudent() {
System.out.println("获取所有学生信息");
return iStudentFeignClient.getAllStudent();
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println("添加学生");
System.out.println(student);
return iStudentFeignClient.addStudent(student);
}
}
客户端提供者:
package com.sms.controller;
import com.sms.entity.RespEntity;
import com.sms.entity.Student;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
@RestController
@RequestMapping("/student")
public class StudentController {
@Value("${server.port}")
private Integer port;
@GetMapping("/{id}")
public RespEntity getStudent(@PathVariable("id") Integer id) {
if (id == 1) {
return new RespEntity(1, "ok"+port, new Student(1, "test1", 12));
}
return new RespEntity(2, "ok"+port, new Student(2, "test2", 11));
}
@GetMapping("/")
public RespEntity getAllStudent() {
return new RespEntity(2, "ok"+port, Arrays.asList(
new Student(1, "test1", 12),
new Student(2, "test2", 11),
new Student(3, "test3", 13)
));
}
@PostMapping("/")
public RespEntity addStudent(@RequestBody Student student) {
System.out.println(student);
return new RespEntity(200, "ok"+port, null);
}
}
Hystrix
概述:
Hystrix是一个用于分布式系统的延迟和容错的开源库。
在分布式系统里,许多依赖不可避免的调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。
解决问题:服务雪崩
在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者"的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sqwieGD-1664275921881)(C:\Users\29295\AppData\Roaming\Typora\typora-user-images\image-20220927182115524.png)]](https://img-blog.csdnimg.cn/f311f053208f4628a84f80d7b56544db.png)
服务正常时:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hsf6pvum-1664275921882)(C:\Users\29295\AppData\Roaming\Typora\typora-user-images\image-20220927182124170.png)]](https://img-blog.csdnimg.cn/29125cd7a14d4f18a2bfcad4bc5a9250.png)
其中一个系统出现问题时:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nyqaRm6Z-1664275921883)(C:\Users\29295\AppData\Roaming\Typora\typora-user-images\image-20220927182128835.png)]](https://img-blog.csdnimg.cn/2deb8611f8cb4e0a926b42f8c313fe39.png) 高流情况下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOrHMLdF-1664275921884)(C:\Users\29295\AppData\Roaming\Typora\typora-user-images\image-20220927182135143.png)]](https://img-blog.csdnimg.cn/c808268fa4004c8580674ac07755ab81.png)
主要功能:
服务降级 | 服务熔断 | 服务限流 |
---|
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback;哪些情况会出发降级:程序运行异常、超时、服务熔断触发服务降级、线程池/信号量打满也会导致服务降级 | 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示,就是保险丝:服务的降级->进而熔断->恢复调用链路 | 秒杀高并发等操作,严禁一窝蜂的过来拥挤, 大家排队,一秒钟N个,有序进行 |
熔断是什么?
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
当检测到该节点微服务调用响应正常后,恢复调用链路。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtdjvgM5-1664275921884)(C:\Users\29295\AppData\Roaming\Typora\typora-user-images\image-20220927182851267.png)]](https://img-blog.csdnimg.cn/55915f7d3da54e759bc2a18fea933149.png)
熔断器三种状态?
关闭(Closed):关闭状态(断路器关闭),所有请求都正常访问。
代理类维护了最近调用失败的次数,如果某次调用失败,则使失败次数加1。如果最近失败次数超过了在给定时间内允许失败的阈值,则代理类切换到断开(Open)状态。此时代理开启了一个超时时钟,当该时钟超过了该时间,则切换到半断开(Half-Open)状态。该超时时间的设定是给了系统一次机会来修正导致调用失败的错误。
打开(Open):打开状态(断路器打开),所有请求都会被降级。
Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。
半开(Half Open):半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。
随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则 继续保持打开,再次进行5秒休眠计时。
涉及到断路器的三个重要参数:
-
快照时间窗: ? 断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。 -
请求总数阀值: ? 在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用次数不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。 -
错误百分比阀值: ? 当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%阀值情况下,这时候就会将断路器打开。
代码:
pom
<!--熔断器依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
yml
feign:
hystrix:
enabled: true
启动类
@EnableCircuitBreaker
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ConsumerStudentApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerStudentApplication.class, args);
}
}
定义降级方法
@HystrixCommand(fallbackMethod = "timeoutfallback")
@GetMapping("/timeout")
public ResponseResult timeout() {
return studentFeignClient.timeout();
}
public ResponseResult timeoutfallback() {
return new ResponseResult(500, "ttimeout---fallback", null);
}
降级方法统一配置【局限性较大,不推荐使用】
@DefaultProperties(defaultFallback = "xxxxfallback")
@RestController
@RequestMapping("/consumerstudent")
public class ConsumerStudent {
@HystrixCommand
@GetMapping("/timeout")
public ResponseResult timeout() {
return studentFeignClient.timeout();
}
@HystrixCommand
@GetMapping("/timeok")
public ResponseResult timeok() {
return studentFeignClient.timeok();
}
public ResponseResult xxxxfallback() {
return studentFeignClient.timeout();
}
}
整合OpenFeign
OpenFeign接口指定对应的降级处理类
package com.woniuxy.consumer.student.feignclient;
import com.woniuxy.common.entity.ResponseResult;
import com.woniuxy.common.entity.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient( value = "provider-student",fallback = StudentFeignClientFallback.class)
public interface StudentFeignClient {
@GetMapping("/student/{sid}")
public ResponseResult<Student> getStudentBySid(@PathVariable("sid") int sid);
@GetMapping("/student/")
public ResponseResult<List<Student>> getAllStudents();
@PostMapping("/student/")
public ResponseResult addStudent(Student student);
@PostMapping("/student/{pageIndex}/{pageSize}")
public ResponseResult getStudentsPager(
@PathVariable("pageIndex") int pageIndex,
@PathVariable("pageSize") int pageSize,
@RequestBody Student student);
@GetMapping("/student/timeout")
public ResponseResult timeout();
@GetMapping("/student/timeok")
public ResponseResult timeok();
}
OpenFeign接口的实现类,定义降级业务逻辑
package com.woniuxy.consumer.student.feignclient;
import com.woniuxy.common.entity.ResponseResult;
import com.woniuxy.common.entity.Student;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class StudentFeignClientFallback implements StudentFeignClient {
@Override
public ResponseResult<Student> getStudentBySid(int sid) {
return new ResponseResult(500, "getStudentBySid---fallback", null);
}
@Override
public ResponseResult<List<Student>> getAllStudents() {
return new ResponseResult(500, "getAllStudents---fallback", null);
}
@Override
public ResponseResult addStudent(Student student) {
return new ResponseResult(500, "addStudent---fallback", null);
}
@Override
public ResponseResult getStudentsPager(int pageIndex, int pageSize, Student student) {
return new ResponseResult(500, "getStudentsPager---fallback", null);
}
@Override
public ResponseResult timeout() {
return new ResponseResult(500, "timeout---fallback", null);
}
@Override
public ResponseResult timeok() {
return new ResponseResult(500, "timeok---fallback", null);
}
}
|