• Spring Cloud(4):Feign的使用


    基于上一篇文章:https://www.cnblogs.com/xuyiqing/p/10867739.html

    使用Ribbon实现了订单服务调用商品服务的Demo

    下面介绍如何使用Feign实现这个Demo

    Feign:伪RPC客户端,底层基于HTTP

    在订单服务的POM中加入依赖

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>

    并在启动类中加入注解,这里已经加入的Ribbon可以保留

    package org.dreamtech.orderservice;
    
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    @EnableFeignClients
    public class OrderServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }

    Feign接口

    package org.dreamtech.orderservice.service;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    @FeignClient(name = "product-service")
    public interface ProductClient {
        @RequestMapping("/api/product/find")
        String findById(@RequestParam(value = "id")int id);
    }

    使用

    package org.dreamtech.orderservice.service.impl;
    
    import com.fasterxml.jackson.databind.JsonNode;
    import org.dreamtech.orderservice.domain.ProductOrder;
    import org.dreamtech.orderservice.service.ProductClient;
    import org.dreamtech.orderservice.service.ProductOrderService;
    import org.dreamtech.orderservice.utils.JsonUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Date;
    import java.util.Map;
    import java.util.UUID;
    
    @Service
    public class ProductOrderServiceImpl implements ProductOrderService {
    
        private final ProductClient productClient;
    
        @Autowired
        public ProductOrderServiceImpl(ProductClient productClient) {
            this.productClient = productClient;
        }
    
        @Override
        public ProductOrder save(int userId, int productId) {
    
            String response = productClient.findById(productId);
            JsonNode jsonNode = JsonUtils.str2JsonNode(response);
    
            ProductOrder productOrder = new ProductOrder();
            productOrder.setCreateTime(new Date());
            productOrder.setUserId(userId);
            productOrder.setTradeNo(UUID.randomUUID().toString());
    
            productOrder.setProductName(jsonNode.get("name").toString());
            productOrder.setPrice(Integer.parseInt(jsonNode.get("price").toString()));
    
            return productOrder;
        }
    }

    工具类

    package org.dreamtech.orderservice.utils;
    
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    import java.io.IOException;
    
    public class JsonUtils {
    
        private static final ObjectMapper objectMapper = new ObjectMapper();
    
        public static JsonNode str2JsonNode(String str) {
            try {
                return objectMapper.readTree(str);
            } catch (IOException e) {
                return null;
            }
        }
    }

    重启Eureka Server和多个product-service:

    访问http://localhost:8781/api/order/save?user_id=1&product_id=1,成功

    使用注意:

    1.Feign的路由和服务的路由必须一致(如这里的/api/product/find)

    2.注意服务名的一致

    3.参数必须加入@RequestParam确保参数名和服务的一致

    4.如果服务的参数加入了@RequestBody,Feign客户端也要加入@RequestBody并修改为POST方式

    5.这里获取到JSON直接解析,实际情况可以抽取公共实体类为JAR包引入返回实体类

    FeignClient原理:

    查看Clien类可以发现,Feign的实现是通过HTTP形式:

            HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
                HttpURLConnection connection = (HttpURLConnection)(new URL(request.url())).openConnection();
                if (connection instanceof HttpsURLConnection) {
                    HttpsURLConnection sslCon = (HttpsURLConnection)connection;
                    if (this.sslContextFactory != null) {
                        sslCon.setSSLSocketFactory(this.sslContextFactory);
                    }
    
                    if (this.hostnameVerifier != null) {
                        sslCon.setHostnameVerifier(this.hostnameVerifier);
                    }
                }

    Client的实现类中:

    发现Feign调用了Ribbon做负载均衡

        public Response execute(Request request, Options options) throws IOException {
            try {
                URI asUri = URI.create(request.url());
                String clientName = asUri.getHost();
                URI uriWithoutHost = cleanUrl(request.url(), clientName);
                RibbonRequest ribbonRequest = new RibbonRequest(this.delegate, request, uriWithoutHost);
                IClientConfig requestConfig = this.getClientConfig(options, clientName);
                return ((RibbonResponse)this.lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig)).toResponse();
            } catch (ClientException var8) {
                IOException io = this.findIOException(var8);
                if (io != null) {
                    throw io;
                } else {
                    throw new RuntimeException(var8);
                }
            }
        }

    处理超时问题:实际情况服务和调用者之间的通信可能较慢,这时候Feign会报错

    如下配置Feign超时实际为10秒

    feign:
      client:
        config:
          default:
            connectTimeout: 10000
            readTimeout: 10000

    Feign默认超时为1秒

    Feign和Ribbon的对比:

    1.Feign里面包含Ribbon,Feign的负载均衡由Ribbon实现

    2.Feign更方便,可以和Hystrix结合

  • 相关阅读:
    将数据导入带模板EXCEL
    c#.net循环将DataGridView中的数据赋值到Excel中,并设置样式
    c#.net对excel的操作——创建一个excel报表两个sheet就是2个表分别添加内容
    Sharepoint2013 中想要将网站另存为模板步骤
    使用SharePoint 2010 母版页
    命令添加用户到组
    随机生成10个数,填充一个数组,然后用消息框显示数组内容,接着计算数组元素的和,将结果也显示在消息框中
    大道至简第五章感悟
    Ljava.lang.Object;@ba8a1dc
    字符串最简单的加密与解密
  • 原文地址:https://www.cnblogs.com/xuyiqing/p/10869026.html
Copyright © 2020-2023  润新知