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的主要内容,如果未能解决你的问题,请参考以下文章