2. Hystrix
2.1 基本公能介绍
hystrix 叫做断路器/熔断器,就是因为微服务模块太多,每一个模块出错都会引起服务整体出错。能通过提前配置的东西,让不影响整个系统、
2.2 基本用法
2.2.1 添加配置文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2.2.2 编写配置文件
spring.application.name=hystrix
server.port=3000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
2.2.3编写一个Service接口
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String hello(){
return restTemplate.getForObject("http://provider/hello",String.class);
}
}
调用这个接口
@RestController
public class HelloController {
@Autowired
HelloService helloService;
/**
* 在这个方法中。我们发起一个远程调用,去掉provider 中提供的/Hello接口,
* 但这个调用可能会失败,
* @return
*/
@GetMapping("/hello")
public String Hello(){
return helloService.hello();
}
}
2.2.4 降级熔断
package com.example.hystrix;
import com.netflix.discovery.converters.Auto;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/**
* 添加这个注解HystricCommand,配置fallbackMethod属性,方法失败时就会调用这个方法
* @return
*/
@HystrixCommand(fallbackMethod = "error")
public String hello(){
return restTemplate.getForObject("http://provider/hello",String.class);
}
/**
* |
* 这个名要和fallbackMethod 属性一致;
* @return
*/
public String error(){
return "当上面的方法,出问题时,就采用降级熔断来解决";
}
}
注意 :
1 一个请求只能执行一次
2. 可以直接执行,可以先入队后执行
通过注解实现请求异步调用的
@HystrixCommand(fallbackMethod = "error")
public Future<String> Async(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
然后调用这个方法
// 异步调用
@GetMapping("/Asyn")
public void Asyn(){
Future<String> async = helloService.Async();
try {
String s = async.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
2.3 异常处理
当服务调用时,如果不是providerde 的原因导致出错,而是consumer本身出错,导致请求失败,即consumer 抛出异常,也会进行服务降级,只不过这是个时候的降级,我们还需要知道哪里出了异样
package com.example.hystrix;
import com.netflix.discovery.converters.Auto;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.Future;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/**
* 添加这个注解HystricCommand,配置fallbackMethod属性,方法失败时就会调用这个方法
* @return
*/
@HystrixCommand(fallbackMethod = "error")
public String hello(){
int i= 1/0;
return restTemplate.getForObject("http://provider/hello",String.class);
}
@HystrixCommand(fallbackMethod = "error")
public Future<String> Async(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
/**
* |
* 这个名要和fallbackMethod 属性一致;
* @return
*/
public String error(Throwable t){
return "当上面的方法,出问题时,就采用降级熔断来解决"+t.getMessage();
}
}
2.4 请求合并
如果consumer中,频繁的的调用provider 中的一个接口,在调用接口时,只是参数不一样时,我们就可以合并请求,这样可以有效提高请求发送效率。
首先在provider 中写个请求合并的接口。
package com.king;
import org.example.commons.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class UserController {
@GetMapping("/user/{ids}") //假设consumer 传过来的多个id 的格式是 1 2 3 4
public List<User> getUserByIds(@PathVariable String ids){
String[] split = ids.split(",");
List<User> users = new ArrayList<>();
for (String s : split) {
User e = new User();
e.setId(Integer.parseInt(s));
users.add(e);
}
return users;
}
}
待续》》》
3.1OpenFegin
前面都是用RestTemplate调用的,存在1个问题
1,繁琐
3.1.1 helloWorld
继续使用proivide中的接口,
新建openfeign模块
项目创建成功后在application中注册到eureka中
3.1.2 在启动类上添加注解
3.1.3 创建helloService接口
定义Helloservice接口,去使用OpenFeign
最后调用HelloController 进行测试
调用结果
参数传值
和普通参数传递的区别
1 参数一定要绑定参数名
2 如果通过header 来传递参数,一定记得中文转码
测试的服务端接口,继续使用provider 提供的接口。
这里主要是在opefeign 中添加调用接口`
package com.example.opefeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.hello();
}
@GetMapping("/hello")
public String hello1(){
String hello = helloService.hello();
System.out.println(hello);
return helloService.hello();
}
}
继承特性
将provider和openfeign 中公共的部分提取出来,一起使用`
日志
5 .1 openFeign 日志级别:
1 NONE :不开启日志 ,就是默认
2.BASIC : 记录请求方法,URL ,响应状态码,执行时间
3. HEADERS: 在BASIC的基础上,添加请求/响应头
4. Full : 在HEADERS基础上,在增加body 以及请求数据