zoukankan      html  css  js  c++  java
  • SpringCloud学习之feign

    一、关于feigin

      feigin是一种模板化,声明式的http客户端,feign可以通过注解绑定到接口上来简化Http请求访问。当然我们也可以在创建Feign对象时定制自定义解码器(xml或者json等格式解析)和错误处理。

    二、添加SpringCloud对feign的支持

    gradle配置:

    compile('org.springframework.cloud:spring-cloud-starter-feign')
    View Code

    feigin最基本使用方法:

     1 interface GitHub {
     2   @RequestLine("GET /repos/{owner}/{repo}/contributors")
     3   List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
     4 }
     5 
     6 static class Contributor {
     7   String login;
     8   int contributions;
     9 }
    10 
    11 public static void main(String... args) {
    12   GitHub github = Feign.builder()
    13                        .decoder(new GsonDecoder())
    14                        .target(GitHub.class, "https://api.github.com");
    15 
    16   // Fetch and print a list of the contributors to this library.
    17   List<Contributor> contributors = github.contributors("OpenFeign", "feign");
    18   for (Contributor contributor : contributors) {
    19     System.out.println(contributor.login + " (" + contributor.contributions + ")");
    20   }
    21 }
    View Code

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

     1 interface LoginClient {
     2 
     3   @RequestLine("POST /")
     4   @Headers("Content-Type: application/xml")
     5   @Body("<login "user_name"="{user_name}" "password"="{password}"/>")
     6   void xml(@Param("user_name") String user, @Param("password") String password);
     7 
     8   @RequestLine("POST /")
     9   @Headers("Content-Type: application/json")
    10   // json curly braces must be escaped!
    11   @Body("%7B"user_name": "{user_name}", "password": "{password}"%7D")
    12   void json(@Param("user_name") String user, @Param("password") String password);
    13 }
    View Code

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

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

     1 final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
     2             @Override
     3             public void checkClientTrusted(
     4                     java.security.cert.X509Certificate[] chain,
     5                     String authType) {
     6             }
     7 
     8             @Override
     9             public void checkServerTrusted(
    10                     java.security.cert.X509Certificate[] chain,
    11                     String authType) {
    12             }
    13 
    14             @Override
    15             public java.security.cert.X509Certificate[] getAcceptedIssuers() {
    16                 return null;
    17             }
    18         }};
    19         final SSLContext sslContext = SSLContext.getInstance("TLSv1");
    20         sslContext.init(null, trustAllCerts,
    21                 new java.security.SecureRandom());
    22         // Create an ssl socket factory with our all-trusting manager
    23         final SSLSocketFactory sslSocketFactory = sslContext
    24                 .getSocketFactory();
    25         Feign.builder().client(new Client.Default(sslSocketFactory, (s, sslSession) -> true));
    View Code

    三、在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
    View Code

    2)创建接口

     1 package com.bdqn.lyrk.consumer.demo.api;
     2 
     3 import org.springframework.cloud.netflix.feign.FeignClient;
     4 import org.springframework.web.bind.annotation.RequestMapping;
     5 
     6 @FeignClient("demo")
     7 public interface DemoConfigService {
     8 
     9     @RequestMapping("/demo.do")
    10     String demoService();
    11 }
    View Code

    注意在接口上加上注解:@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());
        }
    }
    View Code

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

    运行后输出:

    此时我们可以发现使用feign客户端我们访问服务的代码简洁了好多

    4) feign多参数设置方法

    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注解
    View Code

    四、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();
    }
    View Code

      其次定义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 {
    
    }
    View Code

      由于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;
        }
    }
    View Code

      最后@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;
               }
           };
        }
    }
    View Code

      注意:FallbackFactory的泛型参数一定要指定为@FeignClient修饰的接口,同时不建议fallback与fallbackFactory同时使用

      最后 我贴一下服务端的实现代码:

      

    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 / 0);
            return null;
        }
    
        public OrderDTO errorDTO(Integer orderId) {
            OrderDTO orderDTO = new OrderDTO();
            orderDTO.setId(-1);
            orderDTO.setOrderName("错误的订单,请重试");
            return orderDTO;
        }
    }
    View Code

      对于Hystrix可以参考:SpringCloud学习之Hystrix

  • 相关阅读:
    phpcms 短信替换
    phpcms 搭建宣传网站首页
    JDK 8
    MySQL 5.6 date 与 string 的转换和比较
    Illustration of Git branching and merge
    Anti-pattern(反模式)
    Design Patterns笔记
    MyBatis小抄
    MyBatis MapperScannerConfigurer
    MyBatis 批量插入数据对插入记录数的限制
  • 原文地址:https://www.cnblogs.com/niechen/p/8151570.html
Copyright © 2011-2022 走看看