简介
一开始叫 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;
}
}
打包后,分别以两个端口启动项目
- 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
启动发送请求测试
数据压缩
# 开启请求数据压缩
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