声明式服务调用SpringCloud Feign

声明式服务调用SpringCloud Feign

快速入门

创建项目 feign-consumer 9010

pom 依赖

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zk.springcloud.feign</groupId>
    <artifactId>springcloud-feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springcloud-feign</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <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>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

创建应用启动类,并通过 @EnableFeignClients 注解开启 Spring Cloud Feign 的支持功能

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class SpringcloudFeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudFeignApplication.class, args);
    }
}

定义 HelloService 接口,通过 @FeignClient 注解指定服务名来绑定服务,然后再使用 SpringMVC 的注解来绑定具体该服务提供的 REST 接口

这里服务名不区分大小写,所以使用 SERIVCE-USER 和 service-user 都是可以的

@FeignClient("SERIVCE-USER")
@Service
public interface HelloService {

    @RequestMapping("/hello")
    String hello();
}

方法调用

@RestController
public class ConsumerController {

    @Autowired
    HelloService helloService;

    @GetMapping(value = "/feign-consumer")
    public String helloConsumer(){
        return helloService.hello();
    }
}

配置文件

spring.application.name=feign-consumer
server.port=9010

eureka.client.service-url.defaultZone=http://localhost:9001/eureka/,http://localhost:9004/eureka/

测试验证,如之前验证 Ribbon 客户端负载均衡一样,先启动注册中心以及两个 SERVICE-USER ,然后启动 FEIGN-CONSUMER ,多次调用 http://localhost:9010/feign-consumer , 结果与之前 Ribbon 实现时一样的效果 Hello World 9006 和 Hello World 9003 切换显示。依然是利用 Ribbon 维护对 SERVICE-USER 的服务列表信息,并且通过轮询实现了客户端负载均衡。

参数绑定

feign-consumer 9010 , HelloService 添加方法

    @GetMapping(value = "/hello1")
    String hello(@RequestParam("name") String name);

    @GetMapping(value = "/hello2")
    User hello(@RequestHeader("name") String name,@RequestHeader("password") String password);

    @PostMapping(value = "/hello3")
    String hello(@RequestBody User user);

User 对象如下, 这里必须要有 User 的默认构造函数,不然 Spring Cloud Feign 根据 JSON 字符串转换 User 对象会抛出异常

public class User {
    String name;
    String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

对 UserService 9003 项目改造

@FeignClient("SERIVCE-USER")
@Service
public interface HelloService {

    @RequestMapping("/hello")
    String hello();

    @GetMapping(value = "/hello1")
    String hello(@RequestParam("name") String name);

    @GetMapping(value = "/hello2")
    User hello(@RequestHeader("name") String name,@RequestHeader("password") String password);

    @PostMapping(value = "/hello3")
    String hello(@RequestBody User user);
}

在 feign-consumer 9010 项目添加调用

    @GetMapping(value = "/feign-consumer2")
    public String helloConsumer2(){
        StringBuilder sb = new StringBuilder();
        sb.append(helloService.hello()).append("\n");
        sb.append(helloService.hello("DIDI")).append("\n");
        sb.append(helloService.hello("DIDI","123456")).append("\n");
        sb.append(helloService.hello(new User("DIDI","admin"))).append("\n");
        return sb.toString();
    }

访问 http://localhost:9010/feign-consumer2 可获取 Hello World 9003 Hello DIDI User{name=‘DIDI’, password=‘123456’} Hello DIDI, admin

继承特性

创建名为 user-service-api 的 maven 项目

pom 依赖

<?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">
    <modelVersion/>

    <groupId>com.zk.springcloud</groupId>
    <artifactId>springcloud-user-service-api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

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

复制上节中的 User 对象到 user-service-api 工程

创建 HelloService 接口

package com.zk.springcloud;

import org.springframework.web.bind.annotation.*;

@RequestMapping("/refactor")
public interface HelloService {

    @GetMapping(value = "/hello4")
    String hello(@RequestParam("name") String name);

    @GetMapping(value = "/hello5")
    User hello(@RequestHeader("name") String name,@RequestHeader("password") String password);

    @PostMapping(value = "/hello6")
    String hello(@RequestBody User user);
}

对 user-service 和 feign-consumer 重构

对 user-service 重构

添加 user-serivce-api的依赖

        <dependency>
            <groupId>com.zk.springcloud</groupId>
            <artifactId>springcloud-user-service-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

创建 RefactorHelloController 类继承 user-service-api 中定义的 HelloService 接口

package com.zk.springcloud.service;

import com.zk.springcloud.HelloService;
import com.zk.springcloud.User;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RefactorHelloController implements HelloService {
    @Override
    public String hello(@RequestParam("name") String name) {
        return "Hello " + name;
    }

    @Override
    public User hello(@RequestHeader("name") String name,@RequestHeader("password") String password) {
        return new User(name,password);
    }

    @Override
    public String hello(@RequestBody User user) {
        return "Hello " + user.getName() + ", " + user.getPassword();
    }
}

对 feign-consumer 重构

创建 RefactorHelloService 接口

import org.springframework.stereotype.Service;

@FeignClient(value = "SERIVCE-USER")
@Service
public interface RefactorHelloService extends HelloService {

}

添加调用

    @GetMapping(value = "/feign-consumer3")
    public String helloConsumer3(){
        StringBuilder sb = new StringBuilder();
        sb.append(refactorHelloService.hello("MIMI")).append("\n");
        sb.append(refactorHelloService.hello("MIMI","123456")).append("\n");
        sb.append(refactorHelloService.hello(new com.zk.springcloud.User("MIMI","123456"))).append("\n");
        return sb.toString();
    }

访问 http://localhost:9010/feign-consumer3 获得如下结果

Hello MIMI User{name='MIMI', password='123456'} Hello MIMI, 123456

Ribbon 配置

全局配置
ribbon.ConnectTimeout=500
ribbon.ReadTimeout=5000
指定服务配置
serivce-user.ribbon.ConnectTimeout=500
serivce-user.ribbon.ReadTimeout=2000
serivce-user.ribbon.okToRetryOnAllOperations=true
serivce-user.ribbon.MaxAutoRetriesNextServer=2
serivce-user.ribbon.MaxAutoRetries=1
重试机制

feign-consumer 添加上述指定服务配置

user-service 修改如下超时

    @GetMapping(value = "/hello")
    public String hello() throws InterruptedException {
        int sleepTime = new Random().nextInt(3000);
        log.info("sleepTime: " + sleepTime);
        Thread.sleep(sleepTime);
        return "Hello World 9003";
    }

访问 http://localhost:9010/feign-consumer

在 user-service 可以看到重试日志

Hystrix 配置

全局配置
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
#关闭 Hystrix 功能
#feign.hystrix.enabled=false
#关闭熔断功能
#hystrix.command.default.execution.timeout.enabled=false
禁用 Hystrix

全局关闭 Hystrix

#关闭 Hystrix 功能
feign.hystrix.enabled=false

针对某个客户端关闭 Hystrix ,通过使用 @Scope(“prototype”) 注解为指定的客户端配置 Feign.Builder 实例

构建一个关闭 Hystrix 的配置类

@Configuration
public class DisableHystrixConfiguration {

    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder(){
        return Feign.builder();
    }

}

在 HelloService 的 @FeignClient 注解中,通过 configuration 参数引入上面实例的配置

@FeignClient(value = "SERIVCE-USER",configuration = DisableHystrixConfiguration.class)
@Service
public interface HelloService {
	···
}
指定命令配置

针对尝试机制中对 /hello 接口的熔断时间的配置可通过如下配置

hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
服务降级配置

对 feign-consumer 工程进行改造

package com.zk.springcloud.feign;

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

@Component
public class HelloServiceFallBack implements HelloService {
    @Override
    public String hello() {
        return "error";
    }

    @Override
    public String hello(@RequestParam("name") String name) {
        return "error";
    }

    @Override
    public User hello(@RequestHeader("name") String name,@RequestHeader("password") String password) {
        return new User("未知","0");
    }

    @Override
    public String hello(User user) {
        return "error";
    }
}

在服务绑定接口 HelloService 中,通过 @FeignClient 注解的 fallback 属性来指定对应的服务降级实现类

@FeignClient(value = "SERIVCE-USER",fallback = HelloServiceFallBack.class)
@Service
public interface HelloService {

    @RequestMapping("/hello")
    String hello();

    @GetMapping(value = "/hello1")
    String hello(@RequestParam("name") String name);

    @GetMapping(value = "/hello2")
    User hello(@RequestHeader("name") String name,@RequestHeader("password") String password);

    @PostMapping(value = "/hello3")
    String hello(@RequestBody User user);
}

配置文件开启 feign.hystrix

feign.hystrix.enabled=true

将类 DisableHystrixConfiguration 注释

将 user-service 服务关闭,访问 http://localhost:9010/feign-consumer2 获得如下结果:

error error User{name='未知', password='0'} error

其他配置

请求压缩
feign.compression.request.enabled=true
feign.compression.response.enabled=true
#设置压缩的大小下限,超过的才进行压缩,以下配置为默认值
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

日志配置

logging.level.com.zk.springcloud.feign.HelloService=DEBUG

feign-consumer 启动类配置

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class SpringcloudFeignApplication {

    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudFeignApplication.class, args);
    }
}

也可以通过实现配置类,然后在具体的Feign 客户端来指定配置类以实现是否要调整不同的日志界别

@Configuration
public class FullLogConfiguration {

    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

}

调用 http://localhost:9010/feign-consumer

请求详细日志

2018-10-08 14:49:34.051 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] ---> GET http://SERIVCE-USER/hello HTTP/1.1
2018-10-08 14:49:34.051 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] ---> END HTTP (0-byte body)
2018-10-08 14:49:34.872 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] <--- HTTP/1.1 200 (821ms)
2018-10-08 14:49:34.872 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] content-length: 16
2018-10-08 14:49:34.873 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] content-type: text/plain;charset=UTF-8
2018-10-08 14:49:34.873 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] date: Mon, 08 Oct 2018 06:49:34 GMT
2018-10-08 14:49:34.873 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] 
2018-10-08 14:49:34.873 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] Hello World 9003
2018-10-08 14:49:34.873 DEBUG 21632 --- [-SERIVCE-USER-5] com.zk.springcloud.feign.HelloService    : [HelloService#hello] <--- END HTTP (16-byte body)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值