Introduction
Cet article guide la mise en place d'un cluster de microservices minimaliste à l'aide de Spring Cloud Alibaba. Il illustre la configuration d'un service (provider) et d'un client (consumer) qui communiquent via le registre de services Nacos et deux modèles d'appel distincts : OpenFeign et RestTemplate. Le matériel s'appuie sur un atelier pratique.
Préparatifs de l'environnement
La première étape consiste à récupérer les bases de code du serveur (provider) et du client (consumer), puis à démarrer le serveur Nacos qui servira de registre de services.
Acquisition des bases de code
Les deux projets, nommés provider et consumer, sont téléchargés via les commandes suivantes :
git clone https://start.aliyun.com/type=maven-project&language=java&baseDir=provider&groupId=com.example&artifactId=provider&dependencies=sca-nacos-discovery,web provider-repo
git clone https://start.aliyun.com/type=maven-project&language=java&baseDir=consumer&groupId=com.example&artifactId=consumer&dependencies=sca-nacos-discovery,web,cloud-feign consumer-repo
Démarrage de Nacos
Lancer le serveur Nacos en mode standalone :
sh ~/start-nacos.sh
Attendre dans les logs (cat ~/nacos/logs/start.out) le message : "Nacos started successfully in stand alone mode." Le serveur écoute sur le port 65000 par défaut.
Configuration des applications
Les ports et l'adresse du registre doivent être ajustés pour éviter les conflits et permettre la découverte de services.
Configuration du service provider
Dans le fichier application.properties du projet provider :
# Port d'écoute HTTP du service
server.port=8081
# Point d'accès au registre Nacos
spring.cloud.nacos.discovery.server-addr=localhost:65000
# Nom logique sous lequel le service s'enregistre
spring.application.name=echo-service
Configuration du service consumer
Dans le fichier application.properties du projet consumer :
# Port d'écoute HTTP du client
server.port=8082
# Point d'accès au registre Nacos
spring.cloud.nacos.discovery.server-addr=localhost:65000
# Nom logique du service à consommer
provider.service.name=echo-service
Analyse du code source
Cette section détaille l'implémentation des deux projets et les mécanismes d'interappel.
Le service provider (EchoServiceController)
Le provider expose une API REST simple. Un contrôleur avec l'annotation @RestController gère les requêtes.
package com.example.provider.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EchoController {
@GetMapping("/api/echo/{message}")
public String echo(@PathVariable String message) {
return "[Réponse] " + message;
}
}
Cette méthode est accessible via l'URL : http://<host>:8081/api/echo/test.
Le service consumer et ses deux modèles d'appel
Le consumer ne contient pas de logique métier. Il découvre et appelle le service provider via Nacos. Deux approches sont présentées.
1. Utilisation de OpenFeign (Client déclaratif)
Une interface @FeignClient définit le contrat du service distant.
package com.example.consumer.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// 'value' correspond au nom logique du service provider dans Nacos
@FeignClient(name = "${provider.service.name}")
public interface RemoteEchoClient {
@GetMapping("/api/echo/{message}")
String getEcho(@PathVariable("message") String msg);
}
Un contrôleur injecte et utilise cette interface.
package com.example.consumer.controller;
import com.example.consumer.feign.RemoteEchoClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FeignConsumerController {
private final RemoteEchoClient echoClient;
public FeignConsumerController(RemoteEchoClient echoClient) {
this.echoClient = echoClient;
}
@GetMapping("/call-with-feign/{input}")
public String callService(@PathVariable String input) {
return "Réponse via Feign : " + echoClient.getEcho(input);
}
}
2. Utilisation de RestTemplate (Client programmatique)
Un contrôleur utilise un RestTemplate avec une URL logique. La résolution de http://echo-service vers une adresse physique est assurée par un LoadBalancerClient.
package com.example.consumer.controller;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class RestTemplateConsumerController {
// Le RestTemplate est rendu "équilibré de charge" et conscient des services
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/call-with-rest/{input}")
public String callService(@PathVariable String input, RestTemplate restTemplate) {
// 'echo-service' est le nom logique, pas un domaine DNS
String url = "http://echo-service/api/echo/" + input;
return "Réponse via RestTemplate : " + restTemplate.getForObject(url, String.class);
}
}
Construcsion et exécution
Les applications sont empaquetées en fichiers JAR exécutables via Maven.
# Dans le répertoire du provider
mvn clean package -DskipTests
# Dans le répertoire du consumer
mvn clean package -DskipTests
Chaque JAR est ensuite lancé dans un terminal séparé :
java -jar target/provider-0.0.1-SNAPSHOT.jar
java -jar target/consumer-0.0.1-SNAPSHOT.jar
Vérification des fonctionnements
Testez les différents endpoints à l'aide de votre navigateur ou d'un outil comme curl.
- Accès direct au provider :
http://localhost:8081/api/echo/hello→ "[Réponse] hello" - Appel via Feign :
http://localhost:8082/call-with-feign/world→ "Réponse via Feign : [Réponse] world" - Appel via RestTemplate :
http://localhost:8082/call-with-rest/spring→ "Réponse via RestTemplate : [Réponse] spring"
Ces résultats valident que le consumer a pu découvrir le provider dans Nacos et communiquer avec lui en utilisant les deux modèles de programmation.