OpenFeign实践
OpenFeign是一个用于声明式REST客户端的Java框架,它是由Netflix开发的,用于简化在Java应用程序中调用HTTP API的过程。它与Spring Cloud集成得很好,特别适用于微服务架构中的服务间通信。
OpenFeign的核心思想是通过定义接口的方式来描述远程API的调用。你可以使用注解在接口方法上指定HTTP请求的方式、URL、请求参数、请求体、响应处理等信息,而不必手动编写大量的HTTP请求代码。这种方式使得代码更加清晰、可读性更高,并且可以方便地维护和扩展。
主要特点和优势包括:
- 声明式接口定义: 使用Java接口来描述API调用,通过注解来配置请求的方式、路径等信息,使代码具有更高的可读性和可维护性。
- 集成负载均衡: OpenFeign与Ribbon等负载均衡组件集成,可以自动地在多个服务实例中进行负载均衡,提高了系统的可用性和性能。
- 内建Hystrix支持: OpenFeign集成了Hystrix,可以方便地为接口方法添加容错和降级的逻辑,增加了系统的可靠性。
- 与Spring Cloud集成: OpenFeign与Spring Cloud框架无缝集成,可以与Eureka、Config、Zuul等组件协同工作,构建出完整的微服务架构。
- 简化HTTP调用: OpenFeign自动处理HTTP请求和响应,减少了手动编写HTTP请求代码的复杂性。
- 易于测试: 由于OpenFeign接口是基于Java接口定义的,因此可以方便地使用单元测试来测试接口方法。
OpenFeign在微服务架构中发挥着重要的作用,通过简化服务间通信的实现,提高了开发效率并促进了系统的可靠性和可维护性。
OpenFeign简单使用
引入依赖
1 |
|
启动类添加@EnableFeignClients
注解
1 |
|
远程服务客户端
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用作远程服务调用的客户端。
主要属性包括:
- name: 用于指定远程服务的名称。这通常是Eureka注册中心中的服务名称,以便OpenFeign能够根据名称找到对应的服务实例。例如:
@FeignClient(name = "user-service")
。 - url: 如果不使用服务发现(例如Eureka)来定位服务,可以直接指定服务的URL。例如:
@FeignClient(url = "http://localhost:8080")
。 - value: 与
name
属性相同,用于指定远程服务的名称。 - path: 用于指定基础路径,它会被添加到所有接口方法的URL前面。例如:
@FeignClient(name = "user-service", path = "/api")
。 - fallback: 指定一个降级处理的类,当远程服务调用失败时会执行降级逻辑。这个类需要实现相应的接口,并添加
@Component
注解以让Spring能够扫描到。例如:@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
。 - 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);
}
}
执行
最佳实践
RPC 接口和实现各自放在独立的模块中,方便服务调用方重用服务接口,服务接口模块只能包括最基本的模块依靠(过多会导致依靠传递)。
1 |
|
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实践/