思考: 使用RestTemplate+ribbon已经可以完成服务间的调用,为什么还要使用feign?
String restTemplateForObject = restTemplate.getForObject("http://服务名/url?参数" + name, String.class);
存在问题:
1.每次调用服务都需要写这些代码,存在大量的代码冗余
2.服务地址如果修改,维护成本增高
3.使用时不够灵活
说明
https://cloud.spring.io/spring-cloud-openfeign/reference/html/
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,默认实现了负载均衡的效果并且springcloud为feign添加了springmvc注解的支持。
还是在上一个项目的基础之上,在users项目中
1.服务调用方法引入依赖OpenFeign依赖
<!--Open Feign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.入口类加入注解开启OpenFeign支持
@SpringBootApplication @EnableFeignClients //开启openfeign支持 public class Users9999Application { public static void main(String[] args) { SpringApplication.run(Users9999Application.class, args); } }
3.创建一个客户端调用接口
// 此时的product项目中的方法 @RestController @Slf4j public class ProductController { @Value("${server.port}") private int port; @GetMapping("/product/findAll") public Map<String, Object> findAll(){ log.info("商品服务调用成功,当前的服务端口:[{}]",port); HashMap<String, Object> map = new HashMap<>(); map.put("msg","服务调用成功,服务提供的端口为:"+port); map.put("status",true); return map; } } //-------------------------------------------------------------------- package com.md.clients; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; /** * @author md * @Desc 调用商品服务的组件 * @date 2020/12/9 15:30 */ // 指定当前的接口是openfeign组件,value是调用的服务名 @FeignClient("products") public interface ProductClient { @GetMapping("/product/findAll") String findAll(); }
4.使用feignClient客户端对象调用服务
@RestController @Slf4j public class UserController { //注入客户端对象 @Autowired private ProductClient productClient; @GetMapping("/user/findAllFeignClient") public String findAllFeignClient(){ log.info("通过使用OpenFeign组件调用商品服务..."); String msg = productClient.findAll(); return msg; } }
5.访问并测试服务http://localhost:9999/user/findAllFeignClient
服务和服务之间通信,不仅仅是调用,往往在调用过程中还伴随着参数传递,接下来重点来看看OpenFeign在调用服务时如何传递参数
3.GET方式调用服务传递参数
1.商品服务中添加如下方法
@GetMapping("/product/findOne") public Map<String,Object> findOne(String productId){ log.info("商品服务查询商品信息调用成功,当前服务端口:[{}]",port); log.info("当前接收商品信息的id:[{}]",productId); Map<String, Object> map = new HashMap<String,Object>(); map.put("msg","商品服务查询商品信息调用成功,当前服务端口: "+port); map.put("status",true); map.put("productId",productId); return map; }
2.用户服务中在product客户端中声明方法
// @FeignClient("products") public interface ProductClient { @GetMapping("/product/findOne") Map<String, Object> findOne(@RequestParam("productId") String productId); }
注意:使用openfeign的get方式传递参数,参数变量必须通过@RequestParam注解进行修饰
3.用户服务中调用并传递参数
// //注入客户端对象 @RestController @Slf4j public class UserController { @Autowired private ProductClient productClient; @GetMapping("/user/findOne") public Map<String, Object> findOne(String productId){ log.info("用来测试Openfiegn的GET方式参数传递"); Map<String, Object> msg = productClient.findOne(productId); log.info("调用返回信息:[{}]",msg); return msg; } }
4.测试访问
1.商品服务加入post方式请求并接受name
@PostMapping("/product/save") public Map<String,Object> save(String name){ log.info("商品服务保存商品调用成功,当前服务端口:[{}]",port); log.info("当前接收商品名称:[{}]",name); Map<String, Object> map = new HashMap<String,Object>(); map.put("msg","商品查询服务完成当前服务端口: "+port); map.put("status",true); map.put("name",name); return map; }
2.用户服务中在product客户端中声明方法
//value属性用来指定:调用服务名称 @FeignClient("products") public interface ProductClient { @PostMapping("/product/save") String save(@RequestParam("name") String name); }
3.用户服务中调用并传递参数
@Autowired private ProductClient productClient; @PostMapping("/user/save") public Map<String, Object> save(String productName){ log.info("接收到的商品信息名称:[{}]",productName); Map<String, Object> map = productClient.save(productName); log.info("调用成功返回结果: "+map); return map; }
4.测试访问
5.传递对象类型参数
//1.商品服务定义对象 @Data public class Product { private Integer id; private String name; private Date bir; }
//2.商品服务定义接收对象的方法 @PostMapping("/product/saveProduct") public Map<String,Object> saveProduct(@RequestBody Product product){ log.info("商品服务保存商品信息调用成功,当前服务端口:[{}]",port); log.info("当前接收商品名称:[{}]",product); Map<String, Object> map = new HashMap<String,Object>(); map.put("msg","商品服务查询商品信息调用成功,当前服务端口: "+port); map.put("status",true); map.put("product",product); return map; }
//3.将商品对象复制到用户服务中 // 先阶段先这样用着 //4.用户服务中在product客户端中声明方法 @FeignClient("products") public interface ProductClient { @PostMapping("/product/saveProduct") String saveProduct(@RequestBody Product product); } //注意:服务提供方和调用方一定要加入@RequestBody注解
注意:服务提供方和调用方一定要加入@RequestBody注解
// 5.在用户服务中调用保存商品信息服务 //注入客户端对象 @Autowired private ProductClient productClient; @PostMapping("/user/saveProduct") public Map<String, Object> saveProduct(Product product){ log.info("接收到的商品信息:[{}]",product); Map<String, Object> map = productClient.saveProduct(product); log.info("调用成功返回结果: "+map); return map; }
测试
1.超时说明默认情况下,openFiegn在进行服务调用时,要求服务提供方处理业务逻辑时间必须在1S内返回,如果超过1S没有返回则OpenFeign会直接报错,不会等待服务执行,但是往往在处理复杂业务逻辑是可能会超过1S,因此需要修改OpenFeign的默认服务调用超时时间。
2.模拟超时服务提供方加入线程等待阻塞
3.进行客户端调用
4.修改OpenFeign默认超时时间
# 这里的PRODUCTS使用的是大写的方法 feign.client.config.PRODUCTS.connectTimeout=5000 #配置指定服务连接超时 feign.client.config.PRODUCTS.readTimeout=5000 #配置指定服务等待超时 #feign.client.config.default.connectTimeout=5000 #配置所有服务连接超时 #feign.client.config.default.readTimeout=5000 #配置所有服务等待超时
6.OpenFeign调用详细日志展示
0.说明
1.开启日志展示
# 这里的PRODUCTS使用的是大写的方法 feign.client.config.PRODUCTS.loggerLevel=full #开启指定服务日志展示 #feign.client.config.default.loggerLevel=full #全局开启服务日志展示 logging.level.com.baizhi.feignclients=debug #指定feign调用客户端对象所在包,必须是debug级别
2.测试服务调用查看日志
到此这篇关于SpringCloud-OpenFeign组件的使用的文章就介绍到这了,更多相关SpringCloud-OpenFeign组件内容请搜索呐喊教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持呐喊教程!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。