微服务外交官-Feign
创始人
2024-03-11 23:56:14
0

引言

书接上篇 负载均衡组件Ribbon核心-@LoadBalanced-下 我们讲完了Ribbon负载均衡原理之后,接下讲一个SpringCloud Alibaba新的组件:Fegin

前面章节我们使用Ribbon方式实现负载均衡版的远程调用,

//方案4:使用Ribbon方式--带负载均衡
String url =  "http://product-service/products/" + pid;
Product product = restTemplate.getForObject(url, Product.class);
order.setPid(pid);
order.setProductName(product.getName());
order.setProductPrice(product.getPrice());

从实现效果上看没有任何问题,但每次都需要手动拼接URL,有点小麻烦,有没有更加优雅的方式呢?答案是yes:Feign

什么是Feign

Feign是啥?如果我们将所有为微服务比作国家,那Feign就是各国杰出的外交家

Feign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。

Nacos很好的兼容了Feign, Feign默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。

实现案例

还是之前的订单服务调用商品服务,此处使用Feign组件发起远程调用。

步骤1:在shop-order-server项目的pom文件加入Fegin的依赖 


org.springframework.cloudspring-cloud-starter-openfeign

注意:哪一方需要发起远程调用,Feign依赖就加在哪一方

步骤2:启动类OrderServer.java上添加Fegin的扫描注解,注意扫描路径

@SpringBootApplication
@MapperScan("cn.wolfcode.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class,args);}
}

@EnableFeignClients 注解用于扫描后续定义Feign接口,代理生产接口实现类

步骤3:在shop-order-server项目中新增接口IProductFeignService

@FeignClient(name = "product-service")
public interface IProductFeginService {@GetMapping("/products/{pid}")Product get(@PathVariable("pid") Long pid);
}

注意1:@FeignClient 指向要调用服务名

注意2:接口方法定义跟被调用服务接口定义一模一样,只是少了实现

步骤4:修改OrderServiceImpl.java的远程调用方法

@Service
public class OrderServiceImpl extends ServiceImpl implements IOrderService {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate IProductFeginService productFeginService;@Overridepublic Order createOrder(Long pid, Long uid) {Order order = new Order();//商品//方案1:通过restTemplate方式//String url  = "http://localhost:8081/products/" + pid;//Product product = restTemplate.getForObject(url, Product.class);//方案2:使用注册中心api方式-discoveryClient//List instances = discoveryClient.getInstances("product-service");//ServiceInstance instance = instances.get(0);  //当前只有一个//String host = instance.getHost();//int port = instance.getPort();//String url = "http://" + host + ":" + port + "/products/" + pid;//Product product = restTemplate.getForObject(url, Product.class);//方案3:使用注册中心api方式-discoveryClient--带负载均衡//List instances = discoveryClient.getInstances("product-service");//int index = new Random().nextInt(instances.size());//ServiceInstance instance = instances.get(index);//String host = instance.getHost();//int port = instance.getPort();//String url = "http://" + host + ":" + port + "/products/" + pid;//System.out.println("从nacos中获取的url地址:" + url);//Product product = restTemplate.getForObject(url, Product.class);//方案4:使用Ribbon方式--带负载均衡//String url =  "http://product-service/products/" + pid;//Product product = restTemplate.getForObject(url, Product.class);//方案5:使用fegin接口--带负载均衡Product product = productFeginService.get(pid);order.setPid(pid);order.setProductName(product.getName());order.setProductPrice(product.getPrice());//用户order.setUid(1L);order.setUsername("dafei");order.setNumber(1);System.out.println(order);super.save(order);return order;}
}

Feign接口定义成功之后,后续调用跟普通的本地服务层接口一样。

步骤5:重启订单服务,并验证

Feign接口使用原理

看到这,肯定有小伙伴觉得好神奇啊,就定义一个接口就能发起远程访问了,牛逼!其实,细心的朋友应该能看出端倪,Feign接口定义与配置内容都涵盖远程调用所有的参数:

服务名:结合nacos 注册中心可以获取到 ip 与 端口

接口路径:请求路径

接口参数:请求参数

这些参数一组装,不就是完整的服务接口url么~

 

Feign接口定义注意要点

@FeignClient(name = "product-service")
public interface IProductFeginService {@GetMapping("/products/{pid}")Product get(@PathVariable("pid") Long pid);
}

1>@FeignClient 中name为服务提供者在nacos上注册的服务名, 否则报错

Load balancer does not have available server for client:xxxx-service

2>@GetMapping("/products/{pid}") 指定接口路径,必须跟服务提供者提供接口url一样,否则报错

feign.FeignException$NotFound: [404] during [GET] to [http://xxx-service/xxx] 

3> 定义接口参数:如果使用了参数路径方式访问,需要使用@PathVariable("pid") 明确指定路径参数,否则报错

feign.FeignException$NotFound: [404] during [GET] to [http://xxx-service/xxx] 

4>定义接口参数:如果使用普通方式访问,参数需要使用@RequestParam标记,否则报错

@FeignClient(name = "product-service")
public interface IProductFeginService {@GetMapping("/products")Product get(@RequestParam("pid") Long pid);
}
feign.FeignException$MethodNotAllowed: [405] during [GET] to [http://xxxx-service/xxxx?xxx=1]

5>定义接口参数:如果是对象参数,参数需要使用@RequestBody标记(注意fegin接口,controler接口都要),否则报错

@FeignClient(name = "product-service")
public interface IProductFeginService {@GetMapping("/products")Product get(@RequestBody Product product);
}
参数无法获取

6>定义接口参数:如果是对象,可以使用@SpringQueryMap替换上面的@RequestBody

@FeignClient(name = "product-service")
public interface IProductFeginService {@GetMapping("/products")Product get(@SpringQueryMap Product product);
}

7>定义接口参数:如果需要进行文件上传,需要使用@RequestPart注解标记

@FeignClient(name = "product-service")
public interface IProductFeginService {@PostMapping("/upload")void upload(MultipartFile file);
}

8>Feign接口调用默认连接时间是1s,如果电脑较慢,开发中可以配置长一点时间

注意:后面学sentinel 时候,不要配置,会影响观测效果

feign:client:config:default:connectTimeout: 5000  #连接时间,单位毫秒readTimeout: 5000     #操作时间

到这,Feign简单介绍就结束啦,如果有小伙伴想了解Feign源码怎么玩的,那请期待下回分解啦~

相关内容

热门资讯

公安部:立案查处金融领域“黑灰... 北京商报讯(记者 岳品瑜 董晗萱)12月25日,公安部召开新闻发布会,通报公安部和国家金融监督管理总...
感知山东| 胶州市开展“法律护... 为不断深化“陪伴成长”全环境立德树人品牌建设,近日,胶州市司法局李哥庄司法所联合镇宣传办,邀请市“蓝...
天山脚下:检察公益诉讼保卫“地... 每年8月,当天山北坡的阳光变得灼热而明亮,新疆维吾尔自治区昌吉回族自治州吉木萨尔县的田间地头开始弥漫...
围绕关键问题聚焦制度完善建言献... 在十四届全国人大常委会第十九次会议上 本报记者 朱宁宁 十四届全国人大常委会第十九次会议12月23日...
最高法院:名誉侵权、商业诋毁,... 最高法院:名誉侵权、商业诋毁,构成重复起诉? 前后两诉当事人、诉讼标的和诉讼请求不完全一致的,不构成...
柯汶利执导犯罪悬疑片《匿杀》曝... 搜狐娱乐讯 犯罪悬疑片《匿杀》发布终极预告及海报。十五年前,一位自称“小梅”的女孩在火车上惨遭虐杀并...
海南万宁市公安局发布通告 举报... 万宁市公安局关于对举报涉枪涉爆违法犯罪线索予以奖励的通告 为切实有效打击涉枪涉爆违法犯罪活动,提高人...
科技强省需要怎样的金融体系?广... 科技自立自强是国家发展的战略支撑,也是中国式现代化的关键变量。对广东而言,建设科技强省,既是扛起经济...
央行:发挥增量政策和存量政策集... 人民网北京12月25日电 (记者罗知之)据中国人民银行网站消息,中国人民银行货币政策委员会2025年...