【微服务】Feign实现远程调用和负载均衡
目录
1.什么是Feign
2 订单微服务集成Feign
2.1.引入依赖
2.2添加注解
2.3编写Feign的客户端
2.4修改OrderServiceImpl.java的远程调用方法
2.5重启订单服务,并验证
总结
1.什么是Feign
Feign是Spring Cloud提供的⼀个声明式的伪Http客户端, 它使得调⽤远程服务就像调⽤本地服务 ⼀样简单, 只需要创建⼀个接⼝并添加⼀个注解即可。
Nacos很好的兼容了Feign,Feign默认集成了 Ribbon, 所以在Nacos下使⽤Fegin默认就实现了负 载均衡的效果。
2 订单微服务集成Feign
先来看我们以前利用RestTemplate发起远程调用的代码:
/*** Created by mxin5*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class,args);}/*** 远程调用通过resttemplate进行调用,直接进行bean的注入,那个业务需要直接autowired进行注入* @LoadBalanced就可以实现负载均衡,原理就是一个标记,标记Resttemplate发出的请求要被我们的Ribbon进行拦截和处理* */@LoadBalanced@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}
String url = "http://product-service/product/"+productId;Product product = restTemplate.getForObject(url,Product.class);
存在下面的问题:
-
代码可读性差,编程体验不统一
-
参数复杂URL难以维护
所以就采用feign来代替RestTemplate,采用接口的方式进行远程调用和负载均衡。
Fegin的使用步骤如下:
2.1.引入依赖
在shop-order-server项⽬的pom⽂件加⼊Fegin的依赖
<!--fegin组件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
2.2添加注解
在启动类OrderServer.java上添加Fegin的扫描注解,注意扫描路径(默认扫描当前包及其⼦包)
/*** Created by mxin5*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServer {public static void main(String[] args) {SpringApplication.run(OrderServer.class,args);}/*** 远程调用通过resttemplate进行调用,直接进行bean的注入,那个业务需要直接autowired进行注入* @LoadBalanced就可以实现负载均衡,原理就是一个标记,标记Resttemplate发出的请求要被我们的Ribbon进行拦截和处理* */
// @LoadBalanced
// @Bean
// public RestTemplate restTemplate(){
// return new RestTemplate();
// }
}
2.3编写Feign的客户端
在shop-order-server项⽬中新增接⼝ProductFeignApi
/*** Created by mxin5* name的名称一定要和订单服务的服务名保持一致,fallback表示调用失败时的兜底策略* 谁是主调用者谁就集成feign*/
@FeignClient(name = "product-service")
public interface ProductFeignApi {//跟product-service中的controller的接口一致@GetMapping("/product/{pid}")public Product findByPid(@PathVariable("pid") Long pid);
}
@GetMapping("/product/{pid}")public Product findByPid(@PathVariable("pid") Long pid) {...}
这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
服务名称:product-service
请求方式:GET
请求路径:/product/{pid}
请求参数:Long pid
返回值类型:Product
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。
2.4修改OrderServiceImpl.java的远程调用方法
package cn.wolfcode.service.impl;import cn.wolfcode.dao.OrderDao;
import cn.wolfcode.domain.Order;
import cn.wolfcode.domain.Product;
import cn.wolfcode.feign.ProductFeignApi;
import cn.wolfcode.service.OrderService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
@Slf4j //日志
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate ProductFeignApi productFeignApi;//以前的远程调用的方式
// @Autowired
// private RestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", productId);/*** 以前的方式通过Resttemplate进行调用* 问题:1端口号和服务器修改了又要重新进行修改和重启* 2使用集群的方式的话要实现负载均衡,要不断的进行修改,服务器上下线无法感知* 这样就可以使用Springcloud的负载均衡组件feign和注册中心组件nacos* */
// String url = "http://localhost:8081/product/"+productId;
// String url = "http://product-service/product/"+productId; //ribbon实现远程调用和负载均衡//直接传入地址和实体类字节码文件(转成什么对象)进行获取
// Product product = restTemplate.getForObject(url,Product.class);/** 远程调用商品微服务,查询商品信息,通过feign进行调用,并采用负载均衡的方式openfeign直接省略了在启动类进行注入resttemplate的bean,直接调用的时候会将携带服务名去获取本地缓存的服务列表,然后采用轮询或其他负载均衡算法去选择一个可用的服务进行调用*/Product product = productFeignApi.findByPid(productId);log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));//创建订单并保存Order order = new Order();order.setUid(userId);order.setUsername("mxin5");order.setPid(productId);order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderDao.save(order);log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));return order;}
}
2.5重启订单服务,并验证
SpringCloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理(所以我们并不需要编写接口实现类),并注册到Spring容器中。
总结
使用Feign的步骤:
① 引入依赖
② 添加@EnableFeignClients注解
③ 编写FeignClient接口
④ 使用FeignClient中定义的方法代替RestTemplate