spring cloud之服务通信

openfeign(*)

简介

官网:https://cloud.spring.io/spring-cloud-openfeign/reference/html/

Feign是一个声明式的伪HTTP客户端(底层使用RestTemplate),它使编写web服务客户端变得更容易。使用feign,只需要创建一个接口并对其添加注解。它具有可插入的注释支持(可以使用springmvc的注解),可使用feign注解和JAX-RS注解。Feign还支持可插拔编码器和解码器。feign默认集成了Ribbon,默认实现了负载均衡的效果,并且spring cloud为feign添加了springmvc注解的支持

OpenFeign调用

  • 1.引入依赖

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-openfeignartifactId>
dependency>



<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-actuatorartifactId>
dependency>

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
  • 2.配置文件
server.port=8787
spring.application.name=CATEGORY
# consul注册中心地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
  • 3.启动类添加注解@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CategoryApplication {
	
}
  • 4.编写feign客户端接口,添加注解@FeignClient
@FeignClient(value = "PRODUCT") // value:服务名
@Api("商品客户端接口定义")
public interface ProductClient {

    @ApiOperation("简单实现OpenFeign通信")
    @GetMapping("/product")
    String product();

    @ApiOperation("使用拼接参数?k=v&k1=v2方式传参。需指定@RequestParam和属性value")
    @GetMapping("/test")
    String test(@RequestParam(value = "id") Integer id, @RequestParam(value = "productName") String productName);

    @ApiOperation("使用路劲url/{id}/{productName}传参。需指定@PathVariable和属性value")
    @GetMapping("/test1/{id}/{productName}")
    String test1(@PathVariable(value = "id") Integer id, @PathVariable(value = "productName") String productName);

    @ApiOperation("使用对象传递,用JSON方式")
    @PostMapping("/test2")
    String test2(@RequestBody ProductDto productDto);
}
  • 5.Category服务和Product服务进行feign调用测试
@RestController
@Slf4j
public class CategoryController {

    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("category enter......");
        // 使用OpenFeign完成服务间的调用
        //String result = productClient.product();

        // 使用拼接参数?k=v&k1=v2方式传参
        //String result = productClient.test(12, "裙子");

        // 使用路劲/{id}/{productName}传参
        //String result = productClient.test1(12, "裙子");

        // 使用对象传递,用JSON方式
        //String result = productClient.test2(new ProductDto(12, "裙子", 37.80, new Date()));
        
         // 使用数组传参。了解即可
        //String result = productClient.test3(new Integer[]{1, 2, 3});

        // 使用集合传参。服务费需要集合定义到对象中(不能直接使用集合形参)。了解即可
        String result = productClient.test4(new Integer[]{1, 2, 3});
        
        return "category ok!!" + result;
    }
}

@RestController
@Slf4j
@Api("商品服务")
public class ProductController {

    @Value("${server.port}")
    private int port;

    @ApiOperation("简单实现OpenFeign通信")
    @GetMapping("/product")
    public String product() {
        log.info("product enter......");
        return "product ok,当前端口号:" + port;
    }

    @ApiOperation("使用拼接参数?k=v&k1=v2方式传参")
    @GetMapping("/test")
    public String test(@RequestParam Integer id, @RequestParam String productName) {
        log.info("test enter....id={},productName={}", id, productName);
        return "product ok,当前端口号:" + port;
    }

    @ApiOperation("使用路劲url/{id}/{productName}传参")
    @GetMapping("/test1/{id}/{productName}")
    public String test1(@PathVariable Integer id, @PathVariable String productName) {
        log.info("test1 enter....id={},productName={}", id, productName);
        return "product ok,当前端口号:" + port;
    }

    @ApiOperation("使用对象传递,用JSON方式")
    @PostMapping("/test2")
    public String test2(@RequestBody ProductDto productDto) {
        log.info("test enter....productDto={}", productDto);
        return "product ok,当前端口号:" + port;
    }

    @ApiOperation("使用数组传参。了解即可")
    @GetMapping("/test3")
    public String test3(Integer[] ids) {
        for (Integer id : ids) {
            log.info("id:{}",id);
        }
        return "product ok,当前端口号:" + port;
    }

    @ApiOperation("通过集合传参,不能直接使用List等集合接收,需要用对象定义。了解即可")
    @GetMapping("/test4")
    public String test4(ProductIdsDTO productIdsDTO) {
        productIdsDTO.getIds().forEach(id -> log.info("id:{}", id));
        return "product ok,当前端口号:" + port;
    }
}
  • 6.feign接口传参
需要指定传参格式,OpenFeign是一个伪的HTTP客户端,底层用的RestTemplate,所以需要在feign接口中告诉它如何去传参,否则会报错

1.通过?拼接传参。例如:url/?k=v&k1=k2
    @GetMapping("/test")
    String test(@RequestParam(value = "id") Integer id, @RequestParam(value = "productName") String productName);
备注:需要指定@RequestParam注解和value属性值
    
2.通过路径传参。例如:url/{id}/{productName}
 	@GetMapping("/test1/{id}/{productName}")
    String test1(@PathVariable(value = "id") Integer id, @PathVariable(value = "productName") String productName);
备注:需要指定@PathVariable注解和value属性值
    
3.通过对象传参,推荐使用JSON格式
    @PostMapping("/test2")
    String test2(@RequestBody ProductDto productDto);
备注:需要指定@RequestBody注解
    
4.使用数组传参和集合传参,了解即可
    数组传参,feign接口定义:
        @GetMapping("/test3")
        String test3(@RequestParam Integer[] ids);
		备注:必须指定@RequestParam注解
            
   使用集合传参,跟数组传参定义一致。但服务方形参接收定义不一样,详情见"5.feign接口测试"示例

OpenFeign接口调用超时设置

  • OpenFeign接口调用,超时时间默认为1秒,当服务方执行时间超过1秒时,会报错
There was an unexpected error (type=Internal Server Error, status=500).
Read timed out executing GET http://PRODUCT/product
  • 修改OpenFeign默认超时时间配置
# 修改某个服务(PRODUCT)的OpenFeign默认超时时间(默认为1秒)
# PRODUCT:服务名。指定服务连接超时,单位毫秒
feign.client.config.PRODUCT.connect-timeout=3000
# PRODUCT:服务名。指定服务等待超时,单位毫秒
feign.client.config.PRODUCT.read-timeout=3000

# 修改所有服务的OpenFeifn默认超时时间(默认为1秒)
#feign.client.config.default.connect-timeout=3000
#feign.client.config.default.read-timeout=3000

OpenFeign调用日志

  • OpenFeign日志级别
- feign对日志的处理非常灵活,可以为每个feign客户端指定日志记录策略,feign日志的打印只会DEBUG级别做出响应

- 可以为feign客户端配置各自的logger.level对象,日志级别有如下几种
	- NONE:不记录任何日志(默认)
	- BASIC:仅记录请求方法,url,响应状态码及执行时间
	- HEADERS:记录BASIC级别的基础上,记录请求和响应的header
	- FULL:记录请求和响应的header,body及元数据
  • 开启日志打印
# 开启某个feign客户端(PRODUCT)的日志打印
# feign.client.config.PRODUCT.logger-level=full
# 开启所有的feign客户端的日志打印
feign.client.config.default.logger-level=full

# 指定包路径日志打印级别(指定feign客户端的包日志级别必须是debug)
logging.level.com.coolw.cloud.study.feign=debug

日志信息如:
22-01-12 22:51:04.139 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] ---> GET http://PRODUCT/product HTTP/1.1
2022-01-12 22:51:04.139 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] ---> END HTTP (0-byte body)

......

2022-01-12 22:51:05.410 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] <--- HTTP/1.1 200 (1267ms)
2022-01-12 22:51:05.410 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] connection: keep-alive
2022-01-12 22:51:05.410 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] content-length: 33
2022-01-12 22:51:05.410 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] content-type: text/plain;charset=UTF-8
2022-01-12 22:51:05.411 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] date: Wed, 12 Jan 2022 14:51:05 GMT
2022-01-12 22:51:05.411 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] keep-alive: timeout=60
2022-01-12 22:51:05.411 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] 
2022-01-12 22:51:05.413 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] product ok,当前端口号:8788
2022-01-12 22:51:05.413 DEBUG 8324 --- [nio-8787-exec-1] c.coolw.cloud.study.feign.ProductClient  : [ProductClient#product] <--- END HTTP (33-byte body)

你可能感兴趣的:(Spring,Cloud,spring,cloud)