基于数据库的 Feign 服务注册与发现(替代注册中心)
·
Spring Boot 3.5 + MyBatis-Plus 实现基于数据库的 Feign 服务注册与发现(替代注册中心)
一、背景说明
在传统微服务架构中,Feign 通常依赖注册中心(如 Nacos、Eureka
等)进行服务发现。但在部分企业场景中:
- 不希望引入独立注册中心
- 内网环境无法部署中间件
- 希望服务治理完全可控
- 希望服务元数据可持久化、可审计
- 小型/微型/接口型项目,希望架构统一但又无需引入多的中间件
因此,我们实现了一套:
基于数据库的 ServiceInstanceListSupplier 实现, 在不改变 Feign
使用方式的前提下,替代注册中心实现服务发现。
二、适用范围
- Spring Boot 3.5.x
- Spring Cloud 2023.x
- OpenFeign
- MyBatis-Plus
- JDK 21
- 无注册中心或需要替代注册中心场景
特点:
- 不修改 Feign 使用方式
- 支持权重负载均衡
- 支持数据库动态维护服务列表
三、数据库注册表设计
表名:uniops_system_register
核心字段:
字段 说明
system_id spring.application.name
ip 服务IP
port 服务端口
status 1=在线
weight 负载权重
四、核心实现代码
1. 自定义 ServiceInstance
public class DbServiceInstance implements ServiceInstance {
private final String serviceId;
private final String host;
private final int port;
private final Integer weight;
public DbServiceInstance(String serviceId, String host, int port, Integer weight) {
this.serviceId = serviceId;
this.host = host;
this.port = port;
this.weight = weight;
}
public Integer getWeight() {
return weight;
}
@Override
public String getServiceId() {
return serviceId;
}
@Override
public String getHost() {
return host;
}
@Override
public int getPort() {
return port;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public URI getUri() {
return URI.create("http://" + host + ":" + port);
}
@Override
public Map<String, String> getMetadata() {
return Map.of();
}
}
2. 自定义 ServiceInstanceListSupplier
public class DbServiceInstanceSupplier implements ServiceInstanceListSupplier {
private final String serviceId;
private final SystemRegisterMapper mapper;
public DbServiceInstanceSupplier(String serviceId, SystemRegisterMapper mapper) {
this.serviceId = serviceId;
this.mapper = mapper;
}
@Override
public String getServiceId() {
return serviceId;
}
@Override
public Flux<List<ServiceInstance>> get() {
List<SystemRegister> list = mapper.selectList(
new LambdaQueryWrapper<SystemRegister>()
.eq(SystemRegister::getSystemId, serviceId)
.eq(SystemRegister::getStatus, "1")
);
List<ServiceInstance> instances = list.stream()
.map(e -> new DbServiceInstance(
e.getSystemId(),
e.getIp(),
Integer.parseInt(e.getPort()),
e.getWeight() == null ? 1 : e.getWeight()
))
.toList();
return Flux.just(instances);
}
}
3. 全局替换 ServiceInstanceListSupplier
@Configuration
@LoadBalancerClients(defaultConfiguration = GlobalDbLoadBalancerConfiguration.class)
public class GlobalLoadBalancerConfig {
}
子容器配置类(不要加 @Configuration):
public class GlobalDbLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier(
Environment environment,
SystemRegisterMapper mapper) {
String serviceId =
environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new DbServiceInstanceSupplier(serviceId, mapper);
}
}
五、Feign 使用方式保持不变
@FeignClient(name = "wit-ptjk-uni-notice")
public interface NoticeFeign {
@PostMapping("/yx-uni-notice/notice/toDing")
Boolean toDing(DingCondition condition);
}
无需修改调用代码。
六、架构运行流程
Feign
↓
Spring Cloud LoadBalancer
↓
DbServiceInstanceSupplier
↓
MyBatis-Plus
↓
uniops_system_register 表
八、总结
本文实现了:
- 无注册中心的 Feign 服务发现
- 数据库存储服务实例
- 全局替换 ServiceInstanceListSupplier
- 保持 Feign 使用方式完全不变
适合内网、轻量级、强可控场景使用。
更多推荐




所有评论(0)