目录
前言
在微服务架构中,服务之间的通信是一个非常重要的环节。为了简化和高效地进行服务间通信,Spring Cloud 提供了 OpenFeign 这个强大的工具。本文将介绍 OpenFeign 的概念、优点、基本用法以及在实际项目中的应用。也希望通过本文,能够帮助你们在 Spring Cloud 项目中轻松地集成和使用 OpenFeign。
一、什么是OpenFeign?
OpenFeign 是一个声明式的 HTTP 客户端,用于简化微服务间的 HTTP 调用。它集成了 Ribbon 以实现负载均衡,并且与 Eureka、Consul 等服务发现组件无缝对接。通过使用 OpenFeign,开发者只需要定义接口并使用注解来配置 HTTP 请求,而无需编写大量的模板代码。
Feign 的实现
Feign 在 Ribbon + RestTemplate 基础上做了进一步封装, 它来帮助我们定义和实现依赖服务接口的定义。在 Feign 的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是在 Dao 接口上面标注 Mapper 注解,现在是一个 Service 接口上面标注 Feign 注解),即可完成对服务提供方的接口绑定,简化了使用 Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。
Feign 和 OpenFeign 的区别
依赖 | 作用 | |
Feign | org.springframework.cloud spring-cloud-starter-feign | Feign 是 Spring Cloud 组件中的一个轻量级 RESTful 的 HTTP 服务客户端。Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口就可以调用服务注册中心的服务。 |
OpenFeign | org.springframework.cloud spring-cloud-starter-openfeign | OpenFeign 是 Spring Cloud 在Feign 的基础上支持了 SpringMVC的注解如 @RequesMapping 等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。 |
二、OpenFeign的优点
声明式调用:通过注解定义 HTTP 请求,代码更简洁。
集成 Ribbon:支持客户端负载均衡。
支持服务发现:与 Eureka、Consul 等服务发现组件无缝集成。
支持熔断:与 Hystrix、Sentinel 等熔断器集成,提升系统稳定性。
可扩展:支持自定义拦截器、编码器和解码器,便于扩展和定制化。
三、基本用法
新建子工程
配置文件
server:
port: 9091
spring:
application:
name: demo-order
cloud:
nacos:
discovery:
server-addr: 192.168.1.85:8848
namespace: demo
config:
server-addr: 192.168.1.85:8848
prefix: ${spring.application.name}
file-extension: yml
namespace: demo
<dependencies>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
服务注册
新建Controller
引入依赖
user模块引入OpenFeign依赖
创建接口
启动类开启Feign注解
在用户模块的启动类,加上 @EnableFeignClients 注解。
访问测试
如图所示,证明已经访问成功了。
四、@FeignClient 标签的常用属性
@FeignClient 注解是 Spring Cloud OpenFeign 中用于声明一个 Feign 客户端的核心注解。它可以用来指定服务的名称、配置类、负载均衡策略等。下面是 @FeignClient 注解的一些常用属性及其用途:
1、name
name 属性用于指定 Feign 客户端调用的服务名称。这是一个必填属性,通常是注册在服务发现(如 Nacos)中的服务名。
@FeignClient(name = "demo-user")
public interface UserClient {
// ...
}
2、url
url 属性用于指定服务的 URL,通常用于调试或服务未注册到服务发现时。url
属性会覆盖 name
属性。
@FeignClient(name = "demo-user", url = "http://localhost:8080")
public interface UserClient {
// ...
}
3、configuration
configuration 属性用于指定自定义配置类,配置类可以用来定制 Feign 客户端的行为,如请求拦截器、编码器和解码器等。
@FeignClient(name = "demo-user", configuration = FeignConfig.class)
public interface UserClient {
// ...
}
配置类示例
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> template.header("Custom-Header", "CustomHeaderValue");
}
}
4、fallback
fallback 属性用于指定服务降级的实现类。当 Feign 客户端调用失败时,会调用 fallback 指定的类中的方法。
@FeignClient(name = "demo-user", fallback = UserClientFallback.class)
public interface UserClient {
// ...
}
@Component
public class UserClientFallback implements UserClient {
@Override
public User getUserById(Long id) {
return new User(); // 返回一个默认的用户对象
}
}
5、fallbackFactory
fallbackFactory 属性用于指定服务降级的工厂类,该工厂类可以提供更多的上下文信息,例如异常信息。
@FeignClient(name = "demo-user", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
// ...
}
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
@Override
public UserClient create(Throwable cause) {
return new UserClient() {
@Override
public User getUserById(Long id) {
// 返回一个默认的用户对象,并打印异常信息
System.out.println("Fallback cause: " + cause);
return new User();
}
};
}
}
6、path
path 属性用于指定服务的统一前缀路径,在定义 Feign 接口的方法时可以省略该路径。
@FeignClient(name = "demo-user", path = "/api/users")
public interface UserClient {
@GetMapping("/{id}")
User getUserById(@PathVariable("id") Long id);
}
7、decode404
decode404属性用于指定是否将 HTTP 404 响应解码为 Feign 客户端的 fallback,默认值为 false。
@FeignClient(name = "demo-user", decode404 = true)
public interface UserClient {
// ...
}
8、primary
primary属性用于指定该 Feign 客户端是否为主要的 @Primary Bean,这对某些场景下的自动装配很有用,默认值为 true。
@FeignClient(name = "demo-user", primary = false)
public interface UserClient {
// ...
}
9、contextId
contextId 属性用于在多 Feign 客户端实例中区分不同的上下文 ID。特别适用于多个 Feign 客户端指向同一服务时的配置。
@FeignClient(name = "demo-user", contextId = "userClient1")
public interface UserClient1 {
// ...
}
@FeignClient(name = "demo-user", contextId = "userClient2")
public interface UserClient2 {
// ...
}
@FeignClient 注解通过丰富的属性配置,提供了强大的功能来满足不同场景下的微服务调用需求。通过合理使用这些属性,可以定制化 Feign 客户端的行为,提升微服务间的通信效率和容错能力。
五、添加请求头信息
1、在方法参数上添加请求头信息
示例:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
@FeignClient(name = "demo-user")
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id, @RequestHeader("Authorization") String token);
}
在调用接口时,传递请求头参数:
@RestController
public class UserController {
@Autowired
private UserClient userClient;
@GetMapping("/users/{id}")
public User getUser(@PathVariable("id") Long id) {
String token = "xxxxxxxxxxxxxxxxxxxx";
return userClient.getUserById(id, token);
}
}
2、使用 Feign 配置类定义请求拦截器
如果需要在所有请求中添加相同的请求头,可以通过定义一个 Feign 请求拦截器来实现。
定义请求拦截器
创建一个 Feign 配置类,并定义请求拦截器:
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
template.header("Authorization", "xxxxxxxxxxxxxxxxx");
}
};
}
}
应用配置类
在 Feign 客户端接口上指定配置类:
@FeignClient(name = "demo-user", configuration = FeignConfig.class)
public interface UserClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
}
这样,每次调用 UserClient 的方法时,请求头中都会自动包含 Authorization:xxxxxxxxxxxxx
3、动态添加请求头信息
如果需要根据某些条件动态添加请求头信息,可以在拦截器中编写逻辑:
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("Authorization");
if (token != null) {
template.header("Authorization", token);
}
}
}
};
}
}
这种方式可以将来自原始 HTTP 请求的请求头信息传递给 Feign 客户端的请求。
总结
本文介绍了 OpenFeign 的基本概念、优点以及在 Spring Boot 项目中的基本用法。OpenFeign 作为声明式的 HTTP 客户端,大大简化了微服务间的通信,使代码更加简洁和易于维护。在实际项目中,OpenFeign 还提供了许多高级特性,如超时设置、自定义拦截器和熔断器集成等,可以根据具体需求进行灵活配置。