重试器
如何配置重试器?
新建一个EurekaClientFeign 配置类 Feign为我们封装了重试器我们使用只需将其注入到IOC当中
feign没有采用线性的重试机制而是采用的是一种指数级(乘法)的重试机制 每次重试时间 当前重试时间*=1.5
@Configuration
public class FeignClientConfig {
/**
* 创建重试器 (重试周期(50毫秒),最大重试周期(2000毫秒),最多尝试次数 6次 )
* feign没有采用线性的重试机制而是采用的是一种指数级(乘法)的重试机制 每次重试时间 当前重试时间*= 1.5
* @return
*/
@Bean
public Retryer getRetryer() {
return new Retryer.Default(50, SECONDS.toMillis(2), 6);
}
}
我们在日常开发当中,项目中存在很多种Feign 采用的不同的重试机制我们可以通过
configuration = FeignClientConfig.class 来制定Feign使用某种重试器
@FeignClient(value = "Eureka-client", configuration = FeignClientConfig.class)
//value 被调用端的服务应用名 configuration 指定对应的重试器 我们可以指定对应feign 使用哪种重试器
public interface EurekaClientFeign {
@GetMapping(value = "/info")
//被调用端的info方法 返回类型需与抽象方法返回一致
String infoByFeign();
}
日志
当我们在使用Feign接口时 此时调用数据出现异常或者抛出异常我们可以通过日志进行分析查找
因为Feign底层是通过动态代理进行创建 无法通过debug进行调试
1, 将Level加载到容器中
/***
* 如果@FeignClient 的参数configuration = FeignClientConfig.class 没有指定的话 默认重试器是对全局使用
*
*/
@Configuration
public class FeignClientConfig {
/**
* 创建重试器 (重试周期(50毫秒),最大重试周期(2000毫秒),最多尝试次数 6次 )
* feign没有采用线性的重试机制而是采用的是一种指数级(乘法)的重试机制 每次重试时间 当前重试时间*= 1.5
*
* @return
*/
@Bean
public Retryer getRetryer() {
return new Retryer.Default(50, SECONDS.toMillis(2), 6);
}
/**
* 创建日志采用FULL级别 此时是属于全局状态 类似调试器 如果想feign单独指定的 在yml
* 单独配置
* @return
*/
public Logger.Level feignClientRetryer() {
return Logger.Level.FULL;
}
Logger.Level 打印类型
/**
* Controls the level of logging.
*/
public enum Level {
/**
* No logging.
* 无日志 默认值
*/
NONE,
/**
* Log only the request method and URL and the response status code and execution
* time.
* 打印出来请求的方法和url 和响应的状态码 和时间 基本信息
*/
BASIC,
/**
* Log the basic information along with request and response headers.
* 打印基本信息 和请求和响应的头信息
*/
HEADERS,
/**
* Log the headers, body, and metadata for both requests and responses.
* 打印 所有的信息
*/
FULL
}
2.在yml文件中设置对应feign接口的日志打印机别
logging:
level:
com.cx.springcloudfeign.feign.client.EurekaClientFeign: debug
重启feign服务 访问刷新
http://localhost:8888/infoByFeign
日志输出
2020-08-22 13:06:21.099 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] ---> GET http://Eureka-client/info HTTP/1.1
2020-08-22 13:06:21.099 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] ---> END HTTP (0-byte body)
2020-08-22 13:06:21.112 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] <--- HTTP/1.1 200 (11ms)
2020-08-22 13:06:21.112 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] connection: keep-alive
2020-08-22 13:06:21.112 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] content-length: 41
2020-08-22 13:06:21.112 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] content-type: text/plain;charset=UTF-8
2020-08-22 13:06:21.113 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] date: Sat, 22 Aug 2020 05:06:21 GMT
2020-08-22 13:06:21.113 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] keep-alive: timeout=60
2020-08-22 13:06:21.113 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign]
2020-08-22 13:06:21.113 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] welcome:shanghai,your address is shanghai
2020-08-22 13:06:21.113 DEBUG 11772 --- [nio-8888-exec-2] c.c.s.feign.client.EurekaClientFeign : [EurekaClientFeign#infoByFeign] <--- END HTTP (41-byte body)
设置了日志级别我们就能获取的feign在请求和响应的所有信息
Feign复杂使用场景
第一步 在client中加入
两个类
public class Parent {
private int id;
private String name;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Student {
private int id;
private String name;
private String address;
private Parent parent;
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
第二步 在controller层定义需要被Feign接口访问的方法
@GetMapping("/getStudent") //定义映射尽量不适用动词
public Student getStudentByGetRequest(@RequestParam("name") String name,
@RequestParam("address") String address) {
System.out.println("name: " + name);
System.out.println("address: " + address);
Parent parent = new Parent();
parent.setId(10);
parent.setName("parentName");
parent.setAddress("parentAddress");
Student student = new Student();
student.setId(20);
student.setName(name);
student.setAddress(address);
student.setParent(parent);
return student;
}
@PostMapping("/postStudent") //不是良好的rest命名 定义映射尽量不适用动词
public Student getStudentByPostRequest(@RequestBody Parent parent) {
System.out.println(parent.getId());
System.out.println(parent.getName());
System.out.println(parent.getAddress());
Student student = new Student();
student.setId(30);
student.setName("thisStudent");
student.setAddress("theAddress");
student.setParent(parent);
return student;
}
第三步 在feign项目中编写 feign接口
1.先将client中的两个类复制到fegin项目中 此时需要客户端和调用端 实体类保持一致 一个修改另外一个也需要修改
2.将使用的公共实体类 打包成jar 部署到maven当中 当数据发生修改只需要重新install一下
/**
传参时 我们也可以通过map进行传值 feign接口会遍历 map集合中的数据
当做参数
*/
@GetMapping(value = "/getStudent")
Student getStudentByFeign(@RequestParam("name") String name,@RequestParam("address") String address);
/**
@RequestParam("name") String name 将参数直接拼接到url
@RequestBody Parent parent 将参数放到请求体
*/
@PostMapping(value = "/postStudent")
Student postStudentByFeign(@RequestBody Parent parent);
编写service
Student getStudentByFeign(String name, String address);
Student postStudentByFeign(Parent parent);
对应实现类
@Service
public class MyServiceImpl implements MyService {
@Autowired
private EurekaClientFeign eurekaClientFeign;
@Override
public String infoByFeign() {
return eurekaClientFeign.infoByFeign();
}
@Override
public Student getStudentByFeign(String name, String address) {
return this.eurekaClientFeign.getStudentByFeign(name, address);
}
@Override
public Student postStudentByFeign(Parent parent) {
return this.eurekaClientFeign.postStudentByFeign(parent);
}
}
暴露给前端的接口
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/infoByFeign")
public String infoByFeign() {
return this.myService.infoByFeign();
}
@GetMapping(value = "/getStudentByFeign", produces = "application/json;charset=UTF-8") //显示指定返回格式为json 不然有可能返回的是xml
public Student getStudentByFeign() {
return this.myService.getStudentByFeign("zhangsan", "guangzhou");
}
@PostMapping(value = "/postStudentByFeign", produces = "application/json;charset=UTF-8")
public Student postStudentByFeign() {
Parent parent = new Parent();
parent.setId(40);
parent.setName("泽明");
parent.setAddress("北京");
return this.myService.postStudentByFeign(parent);
}
}
此时我们通过浏览器访问
http://localhost:8888/postStudentByFeign
post请求无法在浏览器访问 我们可以通过postman进行测试
http://localhost:8888/postStudentByFeign
总结
我们在编写feign接口的暴露给别人使用时 其实本质上和controller差不多 一个是向其他模块开放接口
一个是想前端开放接口本质是一样