ITPub博客

首页 > 架构设计 > > SpringCloud分布式微服务云架构-SpringCloud feign

SpringCloud分布式微服务云架构-SpringCloud feign

作者:gung123 时间:2020-01-17 15:56:17 0 删除 编辑

feigin是一种模板化,声明式的http客户端,feign可以通过注解绑定到接口上来简化Http请求访问。了解springcloud架构可以加求求:三五三六二四七二五九,当然我们也可以在创建Feign对象时定制自定义解码器(xml或者json等格式解析)和错误处理。
一、添加SpringCloud对feign的支持
gradle配置:

org.springframework.cloud:spring-cloud-starter-feign  

feigin最基本使用方法:  

interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}

static class Contributor {
String login;
int contributions;
}

public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");

// Fetch and print a list of the contributors to this library.
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}

feign发送json与xml的格式的http请求: 

interface LoginClient {

@RequestLine("POST /")
@Headers("Content-Type: application/xml")
@Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")
void xml(@Param("user_name") String user, @Param("password") String password);

@RequestLine("POST /")
@Headers("Content-Type: application/json")
// json curly braces must be escaped!
@Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
void json(@Param("user_name") String user, @Param("password") String password);
}

注意示例中需要添加对gson的支持

feign发送https信任所有证书的代码:

注意示例中需要添加对gson的支持

feign发送https信任所有证书的代码:


 二、在SpringCloud中使用Feign

比如说注册中心有如下服务:
在这里插入图片描述 1)application.yml的配置:
spring:
application:
name: demo-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8080/eureka,http://localhost:8081/eureka
server:
port: 8090

2)创建接口 

package com.bdqn.lyrk.consumer.demo.api;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("demo")
public interface DemoConfigService {

@RequestMapping("/demo.do")
String demoService();
}

注意在接口上加上注解:@FeignClient(“demo”) 注解里的参数是在eureka注册的服务名

3)编写启动类:

package com.bdqn.lyrk.consumer.demo;

import com.bdqn.lyrk.consumer.demo.api.DemoConfigService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class DemoConsumerProvider {

public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoConsumerProvider.class, args);
DemoConfigService demoConfigService = applicationContext.getBean(DemoConfigService.class);
System.out.println(demoConfigService.demoService());
}
}


 注意在启动类上加上@EnableFeignClients来开启Feign功能

运行后输出:

在这里插入图片描述  此时我们可以发现使用feign客户端我们访问服务的代码简洁了好多

  1. feign多参数设置方法
  2. service-api模块的接口定义:

    public interface IBillService {

    @PostMapping("/queryBill")
    List<BillDTO> queryOrders(@RequestBody BillsVO billsVO);
    }

    相关服务实现类:


    @RestController
    public class BillServiceImpl implements IBillService {

    @Autowired
    private BillMapper billMapper;

    @PostMapping("/queryBill")
    @Override
    public List<BillDTO> queryOrders(@RequestBody BillsVO billsVO) {
    return billMapper.query(BeanMap.create(billsVO));
    }
    }

    注意 需要在接口定义与实现类的参数上加@RequestBody注解

    三、feign中的使用Hystrix
      1) 在@FeignClient中有两个属性我们值得关注一下,它们分别是fallBack和fallBackFactory,当然我们系统里要添加Hystrix支持并且在属性文件里设置:  

 feign.hystrix.enabled=true

同样我们要在启动类里加上@EnableCircuitBreaker注解打开Hystrix保护

2) fallBack属性很简单,用来设置降级方法,当feign请求服务失败时所调用的方法, 这里我给出接口的例子:

首先定义一个接口:IOrderService

package com.bdqn.lyrk.service.api;

import com.bdqn.lyrk.service.dto.OrderDTO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


public interface IOrderService {

@GetMapping("/orderId/{orderId}")
OrderDTO getOrderById(@PathVariable("orderId") Integer orderId);

@GetMapping("/errorOrder")
OrderDTO getErrorOrder();
}

其次定义Feign的接口OrderServiceClient继承IOrderService 

package com.bdqn.lyrk.order.service.consumer.feign;

import com.bdqn.lyrk.service.api.IOrderService;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Primary;

@Primary
@FeignClient(value = "ORDER-SERVER", fallBack="FailedOrderServiceClientImpl.class")
public interface OrderServiceClient extends IOrderService {

}


 由于IOrderService不在同一个项目里,而且SpringCloud不推荐服务端和客户端使用同一个接口,所以我采用继承的方式,注意加上@Primary注解以免使用@Autowired时注入失败

在定义实现类:

package com.bdqn.lyrk.order.service.consumer.feign;

import com.bdqn.lyrk.service.dto.OrderDTO;
import org.springframework.stereotype.Component;

@Component
public class FailedOrderServiceClientImpl implements OrderServiceClient {
@Override
public OrderDTO getOrderById(Integer orderId) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(orderId);
orderDTO.setOrderName("服务中失败的订单,id为:" + orderId);
return null;
}

@Override
public OrderDTO getErrorOrder() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderName("服务中失败的订单");
orderDTO.setId(-1);
return orderDTO;
}
}

最后@FeignClient中设置属性fallBack=“FailedOrderServiceClientImpl.class” 就可以了

3) 当我们需要封装服务端的异常信息时,可以指定fallbackFactory属性,请看下面的例子:

package com.bdqn.lyrk.order.service.consumer.feign;

import com.bdqn.lyrk.service.dto.OrderDTO;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class OrderServiceFallbackFactoryImpl implements FallbackFactory<OrderServiceClient> {
@Override
public OrderServiceClient create(Throwable cause) {
return new OrderServiceClient() {
@Override
public OrderDTO getOrderById(Integer orderId) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderName(cause.getMessage());
return orderDTO;
}

@Override
public OrderDTO getErrorOrder() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setOrderName(cause.getMessage());
return orderDTO;
}
};
}
}

注意:FallbackFactory的泛型参数一定要指定为@FeignClient修饰的接口,同时不建议fallback与fallbackFactory同时使——了解springcloud架构可以加求求:三五三六二四七二五九

五、 服务端的实现代码:

package com.bdqn.lyrk.springcloud.order.service;

import com.bdqn.lyrk.service.api.IOrderService;
import com.bdqn.lyrk.service.dto.OrderDTO;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;


@RestController
public class OrderServiceImpl implements IOrderService {

@HystrixCommand(fallbackMethod = "errorDTO",
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")}

)
@GetMapping("/orderId/{orderId}")
@Override
public OrderDTO getOrderById(@PathVariable("orderId") Integer orderId) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(orderId);
orderDTO.setOrderName("订单ID为" + orderId + "的订单");
try {
TimeUnit.SECONDS.sleep(orderId);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

return orderDTO;
}

@Override
public OrderDTO getErrorOrder() {
System.out.println(1 / );
return null;
}

public OrderDTO errorDTO(Integer orderId) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(-1);
orderDTO.setOrderName("错误的订单,请重试");
return orderDTO;
}
}


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69952307/viewspace-3162103/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-11-01

  • 博文量
    200
  • 访问量
    79619