【微服务】Feign实现远程调用和负载均衡

目录

1.什么是Feign

2 订单微服务集成Feign

2.1.引入依赖

2.2添加注解

2.3编写Feign的客户端

2.4修改OrderServiceImpl.java的远程调用方法

2.5重启订单服务,并验证

3.Feign远程调用的工作原理

总结


扫描二维码关注公众号,回复: 14784155 查看本文章

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
    @Bean
    public 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 {
    @Autowired
    private OrderDao orderDao;

    @Autowired
    private ProductFeignApi productFeignApi;

    //以前的远程调用的方式
//    @Autowired
//    private RestTemplate restTemplate;

    @Override
    public 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容器中

3.Feign远程调用的工作原理

注意:服务提供者和服务调用者的写法

1.服务提供者

//服务提供者
@RestController
public class ProductController{
@GetMapping("/product/{pid}")
    public Product findByPid(@PathVariable("pid") Long pid) {
       ...
    }
}

2.服务调用者(注意接口中的参数必须要用注解@PathVariable或者@RequestParam等注解通过反射拿到参数)

@FeignClient(name = "product-service",fallback = ProductFeignFallBack.class)
public interface ProductFeignApi {
    //跟product-service中的controller的接口一致
    @GetMapping("/product/{pid}")
    public Product findByPid(@PathVariable("pid") Long pid);
}

总结

使用Feign的步骤:

① 引入依赖

② 添加@EnableFeignClients注解

③ 编写FeignClient接口

④ 使用FeignClient中定义的方法代替RestTemplate

猜你喜欢

转载自blog.csdn.net/m0_64210833/article/details/129340143