OpenFeign实践

OpenFeign是一个用于声明式REST客户端的Java框架,它是由Netflix开发的,用于简化在Java应用程序中调用HTTP API的过程。它与Spring Cloud集成得很好,特别适用于微服务架构中的服务间通信。

OpenFeign的核心思想是通过定义接口的方式来描述远程API的调用。你可以使用注解在接口方法上指定HTTP请求的方式、URL、请求参数、请求体、响应处理等信息,而不必手动编写大量的HTTP请求代码。这种方式使得代码更加清晰、可读性更高,并且可以方便地维护和扩展。

主要特点和优势包括:

  1. 声明式接口定义: 使用Java接口来描述API调用,通过注解来配置请求的方式、路径等信息,使代码具有更高的可读性和可维护性。
  2. 集成负载均衡: OpenFeign与Ribbon等负载均衡组件集成,可以自动地在多个服务实例中进行负载均衡,提高了系统的可用性和性能。
  3. 内建Hystrix支持: OpenFeign集成了Hystrix,可以方便地为接口方法添加容错和降级的逻辑,增加了系统的可靠性。
  4. 与Spring Cloud集成: OpenFeign与Spring Cloud框架无缝集成,可以与Eureka、Config、Zuul等组件协同工作,构建出完整的微服务架构。
  5. 简化HTTP调用: OpenFeign自动处理HTTP请求和响应,减少了手动编写HTTP请求代码的复杂性。
  6. 易于测试: 由于OpenFeign接口是基于Java接口定义的,因此可以方便地使用单元测试来测试接口方法。

OpenFeign在微服务架构中发挥着重要的作用,通过简化服务间通信的实现,提高了开发效率并促进了系统的可靠性和可维护性。

OpenFeign简单使用

引入依赖

1
2
3
4
5
<!--OpenFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类添加@EnableFeignClients注解

1
2
3
4
5
6
7
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}

远程服务客户端

  • User项目下创建UserController.java和UserService.java 通过/user/{id}提供服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Service
    public class UserService {

    public UserEntity getUser(Long id) {
    UserEntity userEntity = new UserEntity();
    userEntity.setId(id);
    userEntity.setName("用户"+id);
    return userEntity;
    }
    }

    @RestController
    @RequestMapping("/user")
    public class UserController implements UserClient {
    @Autowired
    private UserService userService;

    @Override
    @GetMapping("/{id}")
    public UserEntity getUser(@PathVariable Long id) {
    return userService.getUser(id);
    }
    }
  • Order项目下创建UserClient.java

    1
    2
    3
    4
    5
    @FeignClient("user-service")
    public interface UserClient {
    @GetMapping("/user/{id}")
    UserEntity getUser(@PathVariable Long id);
    }

@FeignClient注解声明式REST客户端接口上标记,以指示该接口将被OpenFeign用作远程服务调用的客户端。

主要属性包括:

  1. name: 用于指定远程服务的名称。这通常是Eureka注册中心中的服务名称,以便OpenFeign能够根据名称找到对应的服务实例。例如:@FeignClient(name = "user-service")
  2. url: 如果不使用服务发现(例如Eureka)来定位服务,可以直接指定服务的URL。例如:@FeignClient(url = "http://localhost:8080")
  3. value:name属性相同,用于指定远程服务的名称。
  4. path: 用于指定基础路径,它会被添加到所有接口方法的URL前面。例如:@FeignClient(name = "user-service", path = "/api")
  5. fallback: 指定一个降级处理的类,当远程服务调用失败时会执行降级逻辑。这个类需要实现相应的接口,并添加@Component注解以让Spring能够扫描到。例如:@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
  6. fallbackFactory:fallback类似,但是这里指定的是一个降级处理工厂,用于创建降级处理类的实例。这通常用于实现更复杂的降级逻辑。例如:@FeignClient(name = "user-service", fallbackFactory = UserServiceFallbackFactory.class)

调用方

  • Order项目下创建OrderService.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Service
    public class OrderService {
    @Autowired
    private UserClient userClient;


    public OrderEntity getOrder(Long id) {
    OrderEntity orderEntity = new OrderEntity();
    orderEntity.setUser(userClient.getUser(id));
    orderEntity.setId(id);
    orderEntity.setTitle("订单"+id);

    return orderEntity;
    }

    }
  • Order项目下创建OrderController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @RestController
    @RequestMapping("/order")
    public class OrderController {
    @Autowired
    private OrderService orderService;
    @GetMapping("/{id}")
    public OrderEntity getOrder(@PathVariable Long id) {
    return orderService.getOrder(id);
    }
    }

执行

image-20230816204051210

最佳实践

image-20230816204027091

RPC 接口和实现各自放在独立的模块中,方便服务调用方重用服务接口,服务接口模块只能包括最基本的模块依靠(过多会导致依靠传递)。

1
2
3
4
5
6
user:
user-service
user-api
order:
order-service
order-api

xxx-api 模块中放服务调用方需求用到的东西,api接口,vo,入参等等。

xxx-service 实现 account-api 供给的接口。

  • user-api

    1
    2
    3
    4
    5
    @FeignClient("user-service")
    public interface UserClient {
    @GetMapping("/user/{id}")
    UserEntity getUser(@PathVariable Long id);
    }
  • user-service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @RestController
    @RequestMapping("/user")
    public class UserController implements UserClient {
    @Autowired
    private UserService userService;

    @Override
    @GetMapping("/{id}")
    public UserEntity getUser(@PathVariable Long id) {
    return userService.getUser(id);
    }
    }

  • Order-service引入user-api

    1
    2
    3
    4
    5
     <dependency>
    <groupId>com.cason</groupId>
    <artifactId>user-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    </dependency>
  • 指定client注入容器

    1
    @EnableFeignClients(clients = {UserClient.class})

OpenFeign实践
https://cason.work/2023/08/16/OpenFeign实践/
作者
Cason Mo
发布于
2023年8月16日
许可协议