乐闻世界logo
搜索文章和话题

How to implement service registration and discovery in Spring Boot microservices?

3月6日 21:58

Spring Boot Microservices Registration and Discovery

Why Service Registration and Discovery

In microservices architecture, service instances change dynamically:

  • Scaling: Instance count constantly changes
  • Failover: Failed instances need automatic removal
  • Dynamic Routing: Clients need to know available service addresses
  • Load Balancing: Distribute requests among multiple instances

Major Registration Centers Comparison

FeatureEurekaNacosConsulZookeeper
DeveloperNetflixAlibabaHashiCorpApache
ConsistencyAPAP/CPCPCP
Health CheckClient heartbeatTCP/HTTP/MySQLTCP/HTTP/gRPCEphemeral nodes
Multi-DCYesYesYesNo
Spring CloudNativeSupportedSupportedSupported
Config CenterNoYesYesNo

Approach 1: Eureka

1. Eureka Server Configuration

Add Dependencies

xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>

Main Class

java
@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }

Configuration

yaml
server: port: 8761 spring: application: name: eureka-server eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ server: enable-self-preservation: false eviction-interval-timer-in-ms: 5000

2. Eureka Client Configuration

Add Dependencies

xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>

Configuration

yaml
server: port: 8081 spring: application: name: user-service eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: prefer-ip-address: true instance-id: ${spring.application.name}:${server.port} lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 10

Approach 2: Nacos (Recommended)

1. Nacos Server Deployment

bash
# Download and start Nacos curl -O https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz tar -xzf nacos-server-2.2.3.tar.gz cd nacos/bin # Start in standalone mode sh startup.sh -m standalone # Console: http://localhost:8848/nacos # Default credentials: nacos/nacos

2. Nacos Client Configuration

Add Dependencies

xml
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

Configuration

yaml
server: port: 8081 spring: application: name: user-service cloud: nacos: discovery: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP metadata: version: v1 region: beijing weight: 1 ephemeral: true

3. Nacos Service Discovery

java
@RestController @RequestMapping("/discovery") @RequiredArgsConstructor public class DiscoveryController { private final DiscoveryClient discoveryClient; private final LoadBalancerClient loadBalancerClient; @GetMapping("/services") public List<String> getServices() { return discoveryClient.getServices(); } @GetMapping("/instances/{serviceName}") public List<ServiceInstance> getInstances(@PathVariable String serviceName) { return discoveryClient.getInstances(serviceName); } @GetMapping("/choose/{serviceName}") public ServiceInstance choose(@PathVariable String serviceName) { return loadBalancerClient.choose(serviceName); } }

Approach 3: Consul

1. Consul Server Deployment

bash
# Download Consul from https://www.consul.io/downloads # Start in dev mode consul agent -dev # Production mode (cluster) consul agent -server -bootstrap-expect=3 -data-dir=/var/consul \ -bind=192.168.1.1 -client=0.0.0.0 -ui -retry-join="provider=aws ..."

2. Consul Client Configuration

Add Dependencies

xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>

Configuration

yaml
server: port: 8081 spring: application: name: user-service cloud: consul: host: localhost port: 8500 discovery: register: true service-name: ${spring.application.name} health-check-path: /actuator/health health-check-interval: 10s instance-id: ${spring.application.name}:${random.value} tags: version=1.0,profile=dev

Inter-Service Communication

1. Using RestTemplate + @LoadBalanced

java
@Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } @Service @RequiredArgsConstructor public class UserService { private final RestTemplate restTemplate; public Order getOrderByUserId(Long userId) { // Use service name instead of specific IP String url = "http://order-service/orders/user/" + userId; return restTemplate.getForObject(url, Order.class); } }

2. Using OpenFeign (Recommended)

Add Dependencies

xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

Enable Feign

java
@SpringBootApplication @EnableFeignClients public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }

Define Feign Client

java
@FeignClient( name = "order-service", fallback = OrderClientFallback.class ) public interface OrderClient { @GetMapping("/orders/{id}") Order getOrderById(@PathVariable("id") Long id); @GetMapping("/orders/user/{userId}") List<Order> getOrdersByUserId(@PathVariable("userId") Long userId); @PostMapping("/orders") Order createOrder(@RequestBody Order order); } @Component @Slf4j public class OrderClientFallback implements OrderClient { @Override public Order getOrderById(Long id) { log.warn("Order service is down, returning fallback for order: {}", id); Order order = new Order(); order.setId(id); order.setStatus("UNKNOWN"); return order; } @Override public List<Order> getOrdersByUserId(Long userId) { return Collections.emptyList(); } @Override public Order createOrder(Order order) { throw new RuntimeException("Order service is unavailable"); } }

Load Balancing

1. Spring Cloud LoadBalancer

java
@Configuration public class LoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer( Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new ReactorServiceInstanceLoadBalancer() { private Random random = new Random(); @Override public Mono<Response<ServiceInstance>> choose(Request request) { ServiceInstanceListSupplier supplier = loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class) .getIfAvailable(); return supplier.get().next().map(instances -> { if (instances.isEmpty()) { return new EmptyResponse(); } int index = random.nextInt(instances.size()); return new DefaultResponse(instances.get(index)); }); } }; } }

Service Gateway

xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
yaml
server: port: 8080 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: user-service uri: lb://user-service predicates: - Path=/api/users/** filters: - StripPrefix=1 - id: order-service uri: lb://order-service predicates: - Path=/api/orders/** filters: - StripPrefix=1

Config Center Integration (Nacos Config)

xml
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
yaml
spring: application: name: user-service profiles: active: dev cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml namespace: dev group: DEFAULT_GROUP
java
@RestController @RefreshScope public class ConfigController { @Value("${user.name:default}") private String userName; @GetMapping("/config") public Map<String, Object> getConfig() { Map<String, Object> config = new HashMap<>(); config.put("userName", userName); return config; } }

Summary

RegistryRecommended ScenarioProsCons
EurekaTraditional Spring CloudMature and stableMaintenance stopped
NacosNew projectsComprehensive features, active communityLearning curve
ConsulMulti-language environmentsCloud-native, feature-richResource intensive
ZookeeperExisting ZK clustersMature and reliableLimited features

Recommendations:

  • New projects: Nacos (comprehensive features, active community)
  • Cloud-native: Consul
  • Legacy projects: Eureka
标签:Spring Boot