0


SpringCloud Alibaba 微服务(三):OpenFeign


前言

在微服务架构中,服务之间的通信是一个非常重要的环节。为了简化和高效地进行服务间通信,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 还提供了许多高级特性,如超时设置、自定义拦截器和熔断器集成等,可以根据具体需求进行灵活配置。


本文转载自: https://blog.csdn.net/qq_32343577/article/details/140762417
版权归原作者 仅此而已丶 所有, 如有侵权,请联系我们删除。

“SpringCloud Alibaba 微服务(三):OpenFeign”的评论:

还没有评论