首页 > 其他分享 >SpringCloud Alibaba-4-Feign远程调用

SpringCloud Alibaba-4-Feign远程调用

时间:2024-03-01 20:33:04浏览次数:44  
标签:Feign String SpringCloud 负载 Alibaba product pname public

远程调用:在分布式系统中,我们使用springboot创建了各种各样服务,那么这些服务之间如何进行远程调用呢。如:订单微服务怎么去调用商品微服务?


Ribbon:是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法服务调用

Ribbon支持的负载均衡策略:

  • BestAvailableRule

  • AvailabilityFilteringRule

  • WeightedResponseTimeRule

  • RetryRule

  • RoundRobinRule

  • RandomRule

  • ZoneAvoidanceRule(默认)



什么是负载均衡?

负载均衡:就是将访问请求进行分摊到多个服务器上进行执行。

分类:

  • 服务端负载均衡——————Ngix
  • 客户端负载均衡——————Nacos

微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。

    服务端负载均衡:指的是发生在服务提供者一方。
        比如:nginx负载均衡。请求到达服务器时,负载均衡器会根据预先设定的算法将请求分配到不同的服务器上,以达到均衡负载的目的。

    客户端负载均衡:指的是发生在服务请求的一方。
        比如:Ribbon负载均衡。请求会通过先某种算法来决定选择哪个可用的服务器,然后将请求发送到选定的服务器上,以达到均衡负载的目的。






1. Feign

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

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







2. 使用Feign

Feign接口定义要点:

  • @FeignClient(name = "xxxx") 中name为服务提供者在nacos上注册的服务名, 否则报错。

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

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

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

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

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

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

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

我们以 SpringCloud Alibaba-3-注册/配置中心 为例,实现用户下单的远程调用


2.1 调整之前的代码,添加新功能

shop-user模块:

	// 根据用户名查询用户信息
	@GetMapping("/getUserInfo/{username}")
	public User getUserInfo(@PathVariable String username){
		LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(User::getUsername, username);
		return userService.getOne(wrapper);
	}


shop-product模块:

	// 根据商品名称获取商品信息
	@GetMapping("/getProductInfo/{pname}")
	public Product getProductInfo(@PathVariable String pname){
		LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(Product::getPname, pname);
		return productService.getOne(wrapper);
	}
	
	// 保存或更新商品信息
	@PutMapping("/saveOrUpdate}")
	public void saveOrUpdate(@RequestBody Product product){
		productService.saveOrUpdate(product);
	}

2.2 引入Feign

shop-order模块:

  1. 添加Feign依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

  1. 开启feign注解
@EnableFeignClients // 开启feign注解
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("com.lihao.mapper")
public class ShopOrderApplication {

	public static void main(String[] args) {
		SpringApplication.run(ShopOrderApplication.class, args);
	}

}

  1. 创建Feign接口
@FeignClient(name = "service-product")
public interface ProductServiceApi {
	
	// 根据商品名称获取商品信息
	@GetMapping("/product/getProductInfo/{pname}")
	public Product getProductInfo(@PathVariable String pname);
	
	// 保存或更新商品信息
	@PutMapping("/product/saveOrUpdate}")
	public void saveOrUpdate(@RequestBody Product product);
}




@FeignClient(name = "service-user")
public interface UserServiceApi {
	
	// 根据用户名查询用户信息
	@GetMapping("/user/getUserInfo/{username}")
	public User getUserInfo(@PathVariable String username);
	
}

  1. 通过Feign远程调用
@RestController
@RequestMapping("/order")
public class OrderController {
	
	@Autowired
	private OrderService orderService;
	
	@GetMapping("/list")
	public List<Order> list(){
		return orderService.list();
	}
	
	@GetMapping("/makeOrder/{username}/{pname}/{number}")
	public Order makeOrder(@PathVariable String username,
	                       @PathVariable String pname,
	                       @PathVariable Integer number){
		return orderService.makeOrder(username, pname, number);
	}
}




@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
	
	@Resource
	private ProductServiceApi productServiceApi;
	
	@Resource
	private UserServiceApi userServiceApi;
	
	/**
	 * @param username 用户名
	 * @param pname    商品名
	 * @param number   数量
	 * @return com.lihao.entity.Order
	 * @author hx
	 * @date 2024/3/1 17:22
	 * @apiNote 创建订单
	 **/
	@Override
	public Order makeOrder(String username, String pname, Integer number) {
		
		// 1. 判断产品是否还有相应数量的产品
		Product product = productServiceApi.getProductInfo(pname);
		if (product==null) {
			throw new RuntimeException("该商品不存在");
		}
		
		int count = product.getStock() - number;
		if (count<number) {
			throw new RuntimeException("产品数量不足");
		}
		
		// 2. 获取用户信息
		User userInfo = userServiceApi.getUserInfo(username);
		if (userInfo==null) {
			throw new RuntimeException("该用户不存在");
		}
		
		// 3. 生成订单
		Order order = new Order();
		order.setUid(userInfo.getUid()); // 用户ID
		order.setUsername(username); // 用户名
		order.setPname(pname); // 商品名称
		order.setPprice(product.getPprice() * number); // 商品总价
		order.setNumber(number); // 购买数量
		this.saveOrUpdate(order);
		
		// 4. 更新产品信息
		product.setStock(count - number);
		productServiceApi.saveOrUpdate(product);
		
		return order;
	}
}






3. 查看Feign负载均衡显现

前要:开启2个商品客户端(localhost:8081,localhost:8082),这里说明一下,真实开发服务器可定是部署在不同的服务器中,ip不一样,端口可以一样。此时为学习,只有一台电脑,使用不同端口模拟一下。


	@Value("${server.port}")
	private String port;
	
	// 根据商品名称获取商品信息
	@GetMapping("/getProductInfo/{pname}")
	public Product getProductInfo(@PathVariable String pname){

		System.out.println("当前服务器端口号:"+port);

		LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(Product::getPname, pname);
		return productService.getOne(wrapper);
	}

现象:成功实现了负载均衡。而且,Feign默认使用的是Rabbion的轮询策略。


我们可以通过修改配置来调整Ribbon的负载均衡策略。
product-service: # 调用的提供者的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

标签:Feign,String,SpringCloud,负载,Alibaba,product,pname,public
From: https://www.cnblogs.com/itlihao/p/18047367

相关文章

  • Alibaba Nacos 控制台默认弱口令
    漏洞描述AlibabaNacos控制台存在默认弱口令 nacos/nacos,可登录后台查看敏感信息影响范围AlibabaNacos漏洞复现发送如下请求:返回200说明成功登录脚本复现python3poc.pyhttps://nacos.taget.com/#!usr/bin/envpython#*-*coding:utf-8*-*importrequestsimpo......
  • Error creating bean with name 'XXX': Bean with name 'senseOneToSomeFeignImpl' ha
    关于Spring框架中的循环依赖问题,您可以尝试以下几种方法来解决:重新定义Bean依赖:重构代码以消除循环依赖。这可能涉及重新设计类,使它们不相互依赖即可运行。使用Setter注入:与构造函数注入相比,使用setter注入。Spring可以更好地处理setter注入的循环依赖,因为对象引用是在对象构造......
  • IDEA Alibaba规范化模板(代码格式化,注释模板化)
    格式化配置阿里模板下载地址:https://github.com/alibaba/p3c/tree/master/p3c-formatter下载下来的文件是针对ecplice的,在IDEA中使用配置文件,需要安装EclipseCodeFormatter插件,安装如下配置格式化模板方式如下注释模板配置修改模板处如下以一下模板修改class、interfa......
  • SpringCloud系列之(十三)FAQ
    关于一些可能出现的报错1.DruidDataSource:testWhileIdleistrue,validationQuerynotset工程启动时可能会报如下错误,这是DruidDataSource保持链接的测试,不影响我们的应用。2.idea未监测到yml文件出现这种情况会造成文件内写配置的时候没有提示正常应该是这样的......
  • SpringCloud系列之(十二)SpringCloud Sleuth分布式请求链路追踪
    SpringCloudSleuth分布式请求链路追踪一、概述1.应用场景​ 在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请......
  • SpringCloud系列之(十一)SpringCloud Stream消息驱动
    SpringCloudStream消息驱动企业中常用的消息中间件ActiveMQRabbitMQRocketMQKafka一、消息驱动概述1.为什么引入SpringCloudStream​ 消息中间件的产品众多(ActiveMQ、RabbitMQ、RocketMQ、Kafka...),学习成本高​ 一个系统中可能使用了多种消息中间件,切换/维护/开发成本......
  • SpringCloud系列之(九)服务配置
    服务配置目前在用的服务配置+服务总线的三套方案Config+BusNaccos(Alibaba)Apollo(携程)上海地区一、SpringCloudConfig分布式配置中心1.概述1.1分布式系统面临的配置问题​ 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现......
  • SpringCloud系列之(八)服务网关
    服务网关类比医院的分诊台一、Zuul由Netflix团队研发,不再使用官网:https://github.com/Netflix/zuul/wiki1.Zuul1.x模型​ Springcloud中所集成的Zuul版本,采用的是Tomcat容器,使用的是传统的ServletI0处理模型。​ 学过尚硅谷web中期课程都知道一个题目,Servlet的生命周期......
  • SpringCloud系列之(七)服务降级
    服务降级一、Hystrix断路器1.概述1.1分布式系统面临的问题复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。![](https://gitee.com/honourer/picturebed/raw/master/SpringCloud/图像(16).png)服务雪崩​ 多个微服务之间调用......
  • SpringCloud系列之(六)服务调用
    服务调用完成微服务之间的分布式调用一、Ribbon1.概述1.1是什么​ SpringCloudRibbon是基于NetflixRibbon实现的一套客户端负载均衡【消费者侧80】的工具。​ 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组......