Microservices With Spring Cloud Alibaba
If you're looking for an alternative to using Spring Cloud Netflix, read on to check out Spring Cloud Alibaba.
Join the DZone community and get the full member experience.
Join For FreeSome days ago, Spring Cloud announced support for several Alibaba components used for building microservices-based architecture. The project is still in the incubation stage, but there is a plan for graduating it from incubation to officially join a Spring Cloud Release Train in 2019. The currently released version 0.0.2.RELEASE is compatible with Spring Boot 2, while the older version 0.0.1.RELEASE is compatible with Spring Boot 1.x. This project seems to be very interesting, and currently, it is the most popular repository amongst Spring Cloud Incubator repositories (around 1.5k likes on GitHub).
Currently, the most commonly used Spring Cloud project for building microservices architecture is Spring Cloud Netflix. As you probably know, this project provides Netflix OSS integrations for Spring Boot apps, including service discovery (Eureka), circuit breaker (Hystrix), intelligent routing (Zuul) and client-side load balancing (Ribbon). The first question that came to my mind when I was reading about Spring Cloud Alibaba was: "Can Spring Cloud Alibaba be an alternative for Spring Cloud Netflix?" The answer is yes, but not entirely. Spring Cloud Alibaba still integrates with Ribbon, which is used for load balancing based on service discovery. Netflix Eureka server is replaced in that case by Nacos.
Nacos (Dynamic Naming and Configuration Service) is an easy-to-use platform designed for dynamic service discovery and configuration and service management. It helps you to build cloud-native applications and microservices platforms easily. Following that definition, you can use Nacos for:
- Service Discovery - you can register your microservice and discover other microservices via a DNS or HTTP interface. It also provides real-time health checks for registered services.
- Distributed Configuration - dynamic configuration service provided by Nacos allows you to manage configurations of all services in a centralized and dynamic manner across all environments. In fact, you can replace Spring Cloud Config Server using it.
- Dynamic DNS - it supports weighted routing, making it easier to implement mid-tier load balancing, flexible routing policies, flow control, and simple DNS resolution services.
Spring Cloud supports another popular Alibaba component — Sentinel. Sentinel is responsible for flow control, concurrency, circuit breaking and load protection.
Our sample system consisting of three microservices and API gateway is very similar to the architecture described in my article Quick Guide to Microservices with Spring Boot 2.0, Eureka and Spring Cloud. The only difference is in the tools used for configuration management and service discovery. The microservice organization-service
calls endpoints exposed by department-service
, while department-service
calls endpoints exposed by employee-service
. An inter-service communication is realized using OpenFeign client. The complexity of the whole system is hidden behind an API gateway implemented using Netflix Zuul.
1. Running Nacos Server
You can run Nacos on both Windows and Linux systems. First, you should download latest stable release provided on their GitHub. After unzipping it, you have to run it in standalone mode by executing the following command:
cmd nacos/bin/startup.cmd -m standalone
By default, Nacos is starting on port 8848. It provides an HTTP API under the context /nacos/v1
, and admin web console under address http://localhost:8848/nacos
. If you take a look at the logs, you will find out that it is just an application written using Spring Framework.
2. Dependencies
As I mentioned before, Spring Cloud Alibaba is still in the incubation stage, therefore it is not included in the Spring Cloud Release Train. That's why we need to include a special BOM for Alibaba in the dependency management section in pom.xml
. We will also use the newest stable version of Spring Cloud, which is now Finchley.SR2
.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Spring Cloud Alibaba provides three starters for the currently supported components. These are spring-cloud-starter-alibaba-nacos-discovery
for service discovery with Nacos, spring-cloud-starter-alibaba-nacos-config
for distributed configuration Nacos, and spring-cloud-starter-alibaba-sentinel
for Sentinel dependencies.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
3. Enabling Distributed Configuration With Nacos
To enable configuration management with Nacos, we only need to include the starter spring-cloud-starter-alibaba-nacos-config
. It does not provide an auto-configured address of the Nacos server, so we need to explicitly set it for the application inside the bootstrap.yml
file.
spring:
application:
name: employee-service
cloud:
nacos:
config:
server-addr: localhost:8848
Our application tries to connect with Nacos and fetch the configuration provided inside the file with the same name as value of the property spring.application.name
. Currently, Spring Cloud Alibaba supports only .properties
file, so we need to create configuration inside the file employee-service.properties
. Nacos comes with an elegant way of creating and managing configuration properties. We can use the web admin console for that. The field Data ID visible on the picture below is, in fact, the name of our configuration file. The list of configuration properties should be placed in the Configuration Content field.
The good news with Spring Cloud Alibaba is that it dynamically refreshes the application configuration after modifications on Nacos. The only thing you have to do in your application is to annotate the beans that should be refreshed with @RefreshScope
or @ConfigurationProperties
. Now, let's consider the following situation. We will modify our configuration a little to add some properties with test data as shown below.
Here's the implementation of our repository bean. It injects all configuration properties with the prefix repository.employees
into the list of employees.
@Repository
@ConfigurationProperties(prefix = "repository")
public class EmployeeRepository {
private List < Employee > employees = new ArrayList < > ();
public List < Employee > getEmployees() {
return employees;
}
public void setEmployees(List < Employee > employees) {
this.employees = employees;
}
public Employee add(Employee employee) {
employee.setId((long)(employees.size() + 1));
employees.add(employee);
return employee;
}
public Employee findById(Long id) {
Optional < Employee > employee = employees.stream().filter(a -> a.getId().equals(id)).findFirst();
if (employee.isPresent())
return employee.get();
else
return null;
}
public List < Employee > findAll() {
return employees;
}
public List < Employee > findByDepartment(Long departmentId) {
return employees.stream().filter(a -> a.getDepartmentId().equals(departmentId)).collect(Collectors.toList());
}
public List < Employee > findByOrganization(Long organizationId) {
return employees.stream().filter(a -> a.getOrganizationId().equals(organizationId)).collect(Collectors.toList());
}
}
Now, you can change some values of properties as shown on the picture below. Then, if you call employee-service
, which is available on port 8090 (http://localhost:8090
), you should see the full list of employees with modified values.
The same configuration properties should be created for our two other microservices,department-service
and organization-service
. Assuming you have already done it, you should have the following configuration entries on Nacos.
4. Enabling Service Discovery With Nacos
To enable service discovery with Nacos, you first need to include the starter spring-cloud-starter-alibaba-nacos-discovery
. The same goes for the configuration server; you also need to set the address of the Nacos server inside the bootstrap.yml
file.
spring:
application:
name: employee-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
The last step is to enable discovery client for the application by annotating the main class with @EnableDiscoveryClient
.
@SpringBootApplication
@EnableDiscoveryClient
@EnableSwagger2
public class EmployeeApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeApplication.class, args);
}
}
If you provide the same implementation for all our microservices and run them, you will see the following list of registered applications in the Nacos web console.
5. Inter-Service Communication
Communication between microservices is realized using the standard Spring Cloud components: RestTemplate
or OpenFeign client. By default, load balancing is realized by the Ribbon client. The only difference in comparison to Spring Cloud Netflix is the discovery server used as a service registry in the communication process. Here's the implementation of the Feign client in department-service
responsible for integration with the endpoint GET /department/{departmentId}
exposed by employee-service
.
@FeignClient(name = "employee-service")
public interface EmployeeClient {
@GetMapping("/department/{departmentId}")
List < Employee > findByDepartment(@PathVariable("departmentId") Long departmentId);
}
Don't forget to enable Feign clients for the Spring Boot application.
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableSwagger2
public class DepartmentApplication {
public static void main(String[] args) {
SpringApplication.run(DepartmentApplication.class, args);
}
}
We should also run multiple instances of employee-service
in order to test load balancing on the client side. Before doing that, we could enable dynamic generation of the port number by setting the property server.port
to 0
inside the configuration stored on Nacos. Now, we can run many instances of a single service using the same configuration settings without the risk of a port number conflict for a single microservice. Let's scale up the number of employee-service
instances.
If you would like to test an inter-service communication, you can call the following methods that use OpenFeign client for calling endpoints exposed by other microservices: GET /organization/{organizationId}/with-employees
from department-service
, and GET /{id}/with-departments
, GET /{id}/with-departments-and-employees
, GET /{id}/with-employees
from organization-service
.
6. Running API Gateway
Now it is the time to run the last component in our architecture — an API Gateway. It is built on top of Spring Cloud Netflix Zuul. It also uses Nacos as a discovery and configuration server.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
After including the required dependencies, we need to enable the Zuul proxy and discovery client for the application.
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@EnableSwagger2
public class ProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ProxyApplication.class, args);
}
}
Here's the configuration of Zuul routes defined for our three sample microservices:
zuul:
routes:
department:
path: /department/**
serviceId: department-service
employee:
path: /employee/**
serviceId: employee-service
organization:
path: /organization/**
serviceId: organization-service
After running the gateway, it exposes the Swagger 2 specification for the API exposed by all defined microservices. Assuming you have run it on port 8080, you can access it under the address http://localhost:8080/swagger-ui.html. Thanks to that, you can call the methods from one, single location.
Conclusion
The sample application's source code is available on GitHub under sample-spring-microservices-new in the branch alibaba. The main purpose of this article was to show you how to replace some popular Spring Cloud components with Alibaba Nacos used for service discovery and configuration management. The Spring Cloud Alibaba project is at an early stage of development, so we can probably expect some new interesting features in the near future. You can find some other examples on the Spring Cloud Alibaba GitHub site here.
Published at DZone with permission of Piotr Mińkowski, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments