Java 微服务之 SpringCloud快速入门day02 Feign

Posted 蓝盒子bluebox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 微服务之 SpringCloud快速入门day02 Feign相关的知识,希望对你有一定的参考价值。

Java 微服务之 SpringCloud快速入门day02 (二)Feign

一、Feign

在前面的学习中,我们使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:

String baseUrl = "http: / /user-service/user / " ;
User user = this.restTemplate.getFor0bject(baseUrl + id,User.class)

如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。

有没有更优雅的方式,来对这些代码再次优化呢?

这就是我们接下来要学的Feign的功能了。

1、简介

为什么叫伪装?

Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。

你不用再自己拼接url,拼接参数等等操作,—切都交给Feign去做。

项目主页:https://github.com/OpenFeign/feign

2、实现

(1)引入依赖

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.1.RELEASE</version>
  </dependency>
(2)添加注解

@EnableFeignClients
(3)创建UserClient接口:Feign客户端



根据服务名拿到了对应的ip地址和端口

package com.itzheng.consumer.client;

import com.itzheng.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("user-service")
public interface UserClient {

    @GetMapping("user/{id}")
    User queryBuId(@PathVariable("id") Long id);

}

表示去user-service这个服务提供方去获取对应的值以及设置对应的参数(即封装远程调用)

(4)完善ConsumerController

package com.itzheng.consumer.web;

import com.itzheng.consumer.client.UserClient;
import com.itzheng.consumer.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("consumer")
@DefaultProperties(defaultFallback = "defaultFallback")
public class ConsumerController {
    //@Autowired
   // private RestTemplate restTemplate;
  /*
    @Autowired
    private DiscoveryClient discoveryClient;
*/
    @Autowired
    private UserClient userClient;

    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {

        return userClient.queryBuId(id);

    }

    @GetMapping("/{id}")
    //@HystrixCommand(fallbackMethod = "queryByIdFallback") //开启线程隔离和服务降级(HystrixCommand失败服务的指令)
/*    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    */
    //fallbackMethod失败的时候调用的方法,成功 时候默认调用下面的方法
    @HystrixCommand(
         commandProperties = {
                 //设置请求的次数为10次当请求请求失败超过5次的时候打开熔断
               @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
                 //短路多久以后开始尝试是否恢复,默认5s  这里设置为10s
               @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
                 //出错百分比阈值,当达到此阈值后,开始短路。默认60%
               @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")
         }
    )
/*
    public String queryById(@PathVariable("id") Long id) {
        if(id % 2 == 0){
            throw new RuntimeException("");
        }

        String url = "http://user-service/user/" + id;
        String user = restTemplate.getForObject(url, String.class);
        return user;
    }
 */
    //fallbackMethod失败的时候调用的方法,与成功时候调用的方法的名称可以不一样,但是返回值和参数必须相同
    public String queryByIdFallback(Long id) {
        return "不好意思,服务器态拥挤了";
    }
    public String defaultFallback() {
        return "不好意思,服务器态拥挤了";
    }


/*

    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        //根据服务id获取实例
        //List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        //从实例当中取出IP和端口
        //ServiceInstance instance = instances.get(0);
        //随机,论询、hash
        //ServiceInstance instance = client.choose("user-service");
        //String url = "http://"+ instance.getHost()+":"+instance.getPort()+"/user/"+id;
        //System.out.println(url);
        //底层还是上述的代码,内部通过拦截器将请求拦截下来,
        //获取到user-service自动去负载均衡后获取ip地址将user-service替换
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }
*/

}

(5)完善ConsumerApplication:开启Feign功能

package com.itzheng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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;
//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication
@EnableFeignClients
@SpringCloudApplication
public class ConsumerApplication {
   /* @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }*/
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}
(6)删除这两个依赖,因为在Feign当中已经有了该依赖


全部依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-demo</artifactId>
        <groupId>com.itzheng.demo</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer-demo</artifactId>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>


    </dependencies>

</project>
(7)开启Feign熔断机制

去掉之前的注解

设置Feign当中熔断的超时时长,开启熔断功能

ribbom:
  ConnectionTimeOut: 500  #如果500毫秒没有获取的请求异常就抛出异常
  ReadTimeOut: 2000 #如果超过2000秒没有获取到请求返回的值就抛出异常
feign:
  hystrix:
    enabled: true  #开启熔断功能

完善UserClient

创建UserClientImpl实现类

package com.itzheng.consumer.client;

import com.itzheng.consumer.pojo.User;
import org.springframework.stereotype.Component;

@Component
public class UserClientImpl implements UserClient {
    @Override
    public User queryBuId(Long id) {

        return null;
    }
}

完善UserClient类

package com.itzheng.consumer.client;

import com.itzheng.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "user-service" ,fallback = UserClientImpl.class)
public interface UserClient {

    @GetMapping("user/{id}")
    User queryBuId(@PathVariable("id") Long id);

}

完善UserClientImpl实现类

package com.itzheng.consumer.client;
import com.itzheng.consumer.pojo.User;
import org.springframework.stereotype.Component;

@Component
public class UserClientImpl implements UserClient {
    @Override
    public User queryBuId(Long id) {
        User user = new User();
        user.setName("未知用户!");
        return user;
    }
}
(8) 重新运行项目


http://localhost:8088/consumer/8


停止user-service

再次访问

(9)请求压缩
(10)日志级别

以上是关于Java 微服务之 SpringCloud快速入门day02 Feign的主要内容,如果未能解决你的问题,请参考以下文章

Java 微服务之 SpringCloud快速入门day01 初始SpringCloud

Java 微服务之 SpringCloud快速入门day01 初始SpringCloud

Java 微服务之 SpringCloud快速入门day01 Eureka注册中心快速入门

Java 微服务之 SpringCloud快速入门day01 Eureka注册中心快速入门

Java 微服务之 SpringCloud快速入门day02 Zuul网关,面向服务的路由,Zuul过滤器

Java 微服务之 SpringCloud快速入门day02 Zuul网关,面向服务的路由,Zuul过滤器