Spring Cloud: use of Feign

Based on the previous article: https://www.cnblogs.com/xuyiqing/p/10867739.html

Using Ribbon to implement the Demo of order service calling commodity service

How to use Feign to implement this Demo

 

Feign: pseudo RPC client, underlying based on HTTP

Add dependency in POM of order service

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

And add notes to the startup class. The Ribbon added here can be reserved

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 interface

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);
}

Use

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;
    }
}

Tool class

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;
        }
    }
}

 

Restart Eureka Server and multiple product services:

Visit http: / / localhost: 8781 / API / order / save? User? Id = 1 & product? Id = 1, success

 

Note for use:

1. The route of feign must be consistent with that of the service (for example, / api/product/find)

2. Pay attention to the consistency of service names

3. Parameter must be added with @ RequestParam to ensure the consistency between parameter name and service

4. If @ RequestBody is added to the service parameters, Feign client also needs to add @ RequestBody and modify it to POST mode

5. The JSON is obtained here for direct parsing. In the actual situation, the public entity class can be extracted to introduce the return entity class for the JAR package

 

FeignClient principle:

 

Looking at the Clien class, we can see that Feign is implemented in the form of 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);
                }
            }

 

In the implementation class of Client:

It is found that Feign calls Ribbon for load balancing

    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);
            }
        }
    }

 

Handling timeout: in the actual situation, the communication between the service and the caller may be slow, and Feign will report an error

The Feign timeout of the following configuration is actually 10 seconds

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

Feign default timeout is 1 second

 

Feign vs. Ribbon:

1.Feign contains the Ribbon. The load balancing of feign is implemented by the Ribbon

2.Feign is more convenient and can be combined with Hystrix

Tags: Java Spring JSON

Posted on Sat, 09 Nov 2019 12:10:09 -0800 by Jackdaw