Feign的使用

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

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

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

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

    
        org.springframework.cloud
        spring-cloud-starter-openfeign
    

并在启动类中加入注解,这里已经加入的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包引入返回实体类

查看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结合

深圳网站建设https://www.sz886.com

你可能感兴趣的:(技术)