阅读 199

Spring Cloud OpenFeign

简介

一开始叫 Feign ,随着Netflix Feign停止开源,Spring Cloud团队在其基础上开发出来的声明式服务调用组件

HelloWorld

  • 1.准备 provider

确保启动了 nacos ,学习 nacos 点击 juejin.cn/post/700294…

然后新建 springboot 项目 provider,这里使用 nacos 作为注册中心,

引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

application.properties

spring.application.name=provider
spring.cloud.nacos.discovery.server-addr=192.168.189.101:8848
复制代码

定义接口

@RestController
public class TestController {
    @Value("${server.port}")
    Integer port;

    @GetMapping("/hello")
    public String hello() {
        return "hello:" + port;
    }
}
复制代码

打包后,分别以两个端口启动项目

image.png

  • 2.准备 consumer

新建 springboot 项目 consumer

引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
        <version>2.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

application.properties

spring.application.name=consumer
server.port=8083
spring.cloud.nacos.discovery.server-addr=192.168.189.101:8848
复制代码

启动类

  • 1.开启 openFeign 配置
  • 2.定义 RestTemplate 模拟负载均衡
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {

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

    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
复制代码

定义 service

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient("provider") // 参数是 provider 的 spring.application.name
public interface ConsumerService {
    @GetMapping("/hello")
    String hello(); // 方法名称无所谓,随便起
}
复制代码

定义 controller

@RestController
public class ConsumerController {
    @Autowired
    ConsumerService service;

    @GetMapping("/hello")
    public String hello() {
        return service.hello();
    }
}
复制代码

启动项目后,多次访问 localhost:8083/hello 进行测试

参数传递

  • 1.参数一定要绑定参数名称
  • 2.如果通过 header 传参,中文一定要转码

继续使用 provider 新添接口

@RestController
public class TestController {
    @Value("${server.port}")
    Integer port;

    @GetMapping("/hello")
    public String hello() {
        return "hello:" + port;
    }

    @PostMapping("/hello2")
    public String hello2(String name) {
        return name;
    }

    @PutMapping("/hello3")
    public User hello3(@RequestBody User user) {
        return user;
    }

    @DeleteMapping("/hello4/{id}")
    public String hello4(@PathVariable int id) {
        return "delete : " + id;
    }
}
复制代码

重新打包,分别运行

consumer 的 service 继续定义接口,key-value参数务必指定名称

@FeignClient("provider")
public interface ConsumerService {
    @GetMapping("/hello")
    String hello(); // 方法名称无所谓,随便起

    @PostMapping("/hello2")
    String hello2(@RequestParam("name") String name);

    @PutMapping("/hello3")
    User hello3(@RequestBody User user);

    @DeleteMapping("/hello4/{id}")
    String hello4(@PathVariable int id);
}
复制代码

consumer 的 controller 继续定义接口

@RestController
public class ConsumerController {
    @Autowired
    ConsumerService service;

    @GetMapping("/hello")
    public String hello() {
        return service.hello();
    }

    @PostMapping("/hello2")
    public String hello2(String name) {
        return service.hello2(name);
    }

    @PutMapping("/hello3")
    public User hello3(@RequestBody User user) {
        return service.hello3(user);
    }

    @DeleteMapping("/hello4/{id}")
    public String hello4(@PathVariable int id) {
        return service.hello4(id);
    }
}
复制代码

启动 consumer 完成测试访问

注意:放在 header 中的参数,一定要编码之后传递

继承特性

将 provider 和 consumer 中公共部分提取出来,一起使用

这里我们重新创建几个项目,重新搭建项目

新建 maven 项目 nacosfeign,然后创建4个子项目

  • commons 和 openapi 是 maven 项目
  • provider 和 consumer 是 springboot 项目

commons

只有一个实体类

public class User {
    private Long id;
    private String name;
    // getter and setter
}
复制代码

openapi

依赖

<dependencies>
    <dependency>
        <groupId>org.southyin</groupId>
        <artifactId>commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
</dependencies>
复制代码

提供公共接口

import org.southyin.model.User;
import org.springframework.web.bind.annotation.*;

public interface IConsumerService {
    @GetMapping("/hello1")
    String hello1(@RequestParam("name") String name);

    @PostMapping("/hello2")
    String hello2(@RequestBody User user);

    @PutMapping("/hello3")
    String hello3(@RequestBody User user);

    @DeleteMapping("/hello4/{id}")
    String hello4(@PathVariable("id") int id);
}
复制代码

provider

依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.southyin</groupId>
        <artifactId>openapi</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

配置

spring.application.name=provider
spring.cloud.nacos.discovery.server-addr=192.168.189.101:8848
server.port=8080
复制代码

提供接口,这里不需要写映射了,因为继承了IConsumerService

@RestController
public class ProviderController implements IConsumerService {

    @Value("${server.port}")
    Integer port;

    @Override
    public String hello1(String name) {
        return name+port;
    }

    @Override
    public String hello2(User user) {
        return user.getName()+port;
    }

    @Override
    public String hello3(User user) {
        return user.getName()+port;
    }

    @Override
    public String hello4(int id) {
        return id+port+"";
    }
}
复制代码

consumer

依赖

这里注意,由于SpringCloud Feign在Hoxton.M2 RELEASED版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer,所以不引入spring-cloud-loadbalancer会报错,同时把 nacos 中 ribbon 忽略掉, 而且引入 loadbalancer 依赖,需要 springboot 版本 2.4 以上才可以

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>org.southyin</groupId>
        <artifactId>openapi</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </exclusion>
        </exclusions>
        <version>2.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        <version>2.2.4.RELEASE</version>
    </dependency>
</dependencies>
复制代码

配置

server.port=1111
spring.application.name=consumer
spring.cloud.nacos.discovery.server-addr=192.168.189.101:8848
复制代码

启动类

@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
复制代码

service

@FeignClient("provider")
public interface ConsumerService extends IConsumerService {}
复制代码

接口

@RestController
public class ConsumerController {
    @Autowired
    ConsumerService consumerService;

    @GetMapping("/c1")
    public String c1(String name) {
        return consumerService.hello1(name);
    }

    @PostMapping("/c2")
    public String c2(@RequestBody User user) {
        return consumerService.hello2(user);
    }

    @PutMapping("/c3")
    public String c3(@RequestBody User user) {
        return consumerService.hello3(user);
    }

    @DeleteMapping("/c4/{id}")
    public String c4(@PathVariable("id") int id) {
        return consumerService.hello4(id);
    }
}
复制代码

将父级项目先install一下,将 provider 打包后,以 java -jar xxxxxxx --server.port 方式启动两个,然后再启动 consumer

访问 consumer 接口完成测试

日志配置

日志级别一共分为 4 种

  • NONE:不开启日志,默认就是这个选项
  • BASIC:记录请求方法、URL、响应状态码、执行时间
  • HEADERS:在 BASIC 基础上,加载请求头、响应头
  • FULL:在 HEADERS 基础上,再增加 body 和 元数据

可以通过 bean 来配置

import feign.Logger;
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    Logger.Level level() {
        return Logger.Level.FULL;
    }
}
复制代码

application 配置中就像 mybatis 配置那样即可

logging.level.org.southyin.consumer.service=debug
复制代码

启动发送请求测试

image.png

数据压缩

# 开启请求数据压缩
feign.compression.request.enabled=true
# 开启响应数据压缩
feign.compression.response.enabled=true
# 压缩数据类型
feign.compression.request.mime-types=text/html,application/json
# 压缩数据下限
feign.compression.request.min-request-size=2048
复制代码
文章分类
后端
文章标签