In the previous articles of this series, we focused on developing orchestration services to enable microservices. We implemented a Discovery Server to let applications consume services without knowing their exact location, and a Configuration Server to allow microservices to run in multiple environments without any modifications in the microservices themselves.
In this article, we’ll implement the first two functional microservices: A REST web service and a web UI for it.
Why do we need this?
Each service, or microservice, is typically developed and operated by independent development teams. The whole application is formed by several independently deployable services running in their own processes, which enables continuous delivery of single-purpose services. In short, microservices can be implemented, maintained, and deployed independently by separate development teams.
Although microservices are developed more or less independently, they depend on other services to fulfill their function. In this example, we are using a well-known communication mechanism: RESTful web services.
Suppose we have two independent teams. The first one is developing a RESTful web service that allows customers to consume data from their systems. The second one is developing a web application to allow customers to consume data using a web UI in the browser. It makes sense to let the web UI consume the RESTful web service the same way customers can consume it from their systems.
Implementing a REST web service
Use Spring Initializr to create a new Spring Boot application named biz-application and include the Eureka Discovery, Config Client, JPA, Rest Repositories, Rest Repositories HAL browser, Hystrix, Actuator, and DevTools (optional) dependencies:
Open up the BizApplication
class and activate the discovery client by using the following annotations:
@SpringBootApplication @EnableDiscoveryClient public class BizApplication { ... }
Remove the application.properties
file and create a new bootstrap.yml
file with the following content:
spring: application.name: biz-application cloud.config: discovery: enabled: true serviceId: config-server eureka: client: serviceUrl: defaultZone: http://localhost:7001/eureka/ registryFetchIntervalSeconds: 1 instance: leaseRenewalIntervalInSeconds: 1
This configures the application for using the Discovery and Configuration servers. The rest of the configuration comes from the Configuration Server which in turn is read from GitHub, or your local Git repository, depending on your configuration. The default configuration from GitHub includes a connection to a file-based H2 database located in the h2-database
directory inside your home directory. You cannot use an in-memory database with this example, if you want to replicate the biz-application
microservice. If you do, every instance of biz-application
will create a new database.
Implement a simple domain class with JPA annotations, to configure the persistence to the database, as follows:
@Entity public class Company { @Id @GeneratedValue private Long id; @NotNull @Size(min = 1) private String name; @NotNull @Size(min = 1) private String twitterUsername; ... setters and getters ... }
Define a repository interface and expose it a REST web service by marking it with the @RepositoryRestResource
annotation:
@RepositoryRestResource public interface CompanyRepository extends CrudRepository<Company, Long> { }
You don’t need to implement this interface. Spring will implement it at runtime.
Make sure the discovery-server
and config-server
applications are running and then compile and run the application by executing the following on the command line:
cd biz-application mvn package java -Dserver.port=9601 -jar target/biz-application-0.0.1-SNAPSHOT.jar
Point your browser to http://localhost:9601 to see the HAL Browser for Spring Data Rest. This is a tool that allows you to “navigate” the web service for testing purposes. Try the /companies
endpoint by typing it in the text field in the Explorer section and click the Go! button.
Consuming a REST web service
Use Spring Initializr to create a new Spring Boot application named admin-application
and include the Eureka Server, Config Client, Feign, HATEOAS, Vaadin, Validation, Hystrix, Actuator, and DevTools (optional) dependencies.
Open up the AdminApplication
class and activate the discovery client, circuit breaker, Feign clients, and hypermedia support by using the following annotations:
@SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker @EnableFeignClients @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) public class AdminApplication { ... }
Remove the application.properties
file and create a new bootstrap.yml
file similar to the one in the biz-application
. Remember to use biz-application as the name of the application. The default configuration from GitHub configures a client-side load balancer with Ribbon and a circuit breaker with Hystrix.
Create a simple domain class as follows:
public class Company implements Serializable { private Long id; @NotNull @Size(min = 1) private String name; @NotNull @Size(min = 1) private String twitterUsername; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Company company = (Company) o; return id != null ? id.equals(company.id) : company.id == null; } @Override public int hashCode() { return id != null ? id.hashCode() : 0; } ... getters and setters ... }
Create a Feign client that connects to the web service provided by the biz-application
microservice:
@FeignClient(name = "${biz-application.name:null}") public interface CompanyService { @RequestMapping("/companies") Resources<Company> findAll(); @RequestMapping(value = "/companies", method = RequestMethod.POST) Company add(@RequestBody Company company); @RequestMapping(value = "/companies/{id}", method = RequestMethod.PUT) Company update(@PathVariable("id") Long id, @RequestBody Company company); @RequestMapping(value = "/companies/{id}", method = RequestMethod.DELETE) void delete(@PathVariable("id") Long id); }
Notice how thanks to the Discovery Server, we can use the name of the application serving the web service (biz-application
) instead of a URL. This allows the team developing the biz-application
to deploy their microservice anywhere. This also allows them to replicate the application as many times as they want, without having to modify the clients of the service. The previous Feign client uses a client-side load balancer that consumes one instance of biz-application
at a time in a round-robin fashion. Since the biz-application
is a stateless service, it doesn’t need to worry about replicating any state among the running instances.
Implementing a CRUD web UI for this service can be quickly done with Vaadin and the Crud UI add-on. Add the following dependency in the pom.xml
file:
<dependency> <groupId>org.vaadin.crudui</groupId> <artifactId>crudui</artifactId> <version>2.1.5</version> </dependency>
Implement a new VaadinUI
class as follows:
@SpringUI(path = "/") public class VaadinUI extends UI { private final CompanyService companyService; public VaadinUI(CompanyService companyService) { this.companyService = companyService; } @Override protected void init(VaadinRequest request) { Label title = new Label("Companies"); title.addStyleName(ValoTheme.LABEL_H2); GridCrud<Company> crud = new GridCrud<>(Company.class); crud.getGrid().setColumns("name", "twitterUsername"); crud.getCrudFormFactory().setVisibleProperties("name", "twitterUsername"); crud.getCrudFormFactory().setUseBeanValidation(true); crud.setFindAllOperation(() -> companyService.findAll().getContent()); crud.setAddOperation(company -> companyService.add(company)); crud.setUpdateOperation(company -> companyService.update(company.getId(), company)); crud.setDeleteOperation(company -> companyService.delete(company.getId())); VerticalLayout mainLayout = new VerticalLayout(title, crud); setContent(mainLayout); } }
The SpringUI
annotation makes instances of the class Spring-managed beans. The path
parameter configures the route you can use in the browser to see this UI. The init
method uses Vaadin Framework to add a Label
and a GridCrud
component to the UI inside a VerticalLayout
.
Compile the application, and run it by executing the following in the command line:
cd admin-application mvn package java -Dserver.port=9401 -jar target/admin-application-0.0.1-SNAPSHOT.jar
Point your browser to http://localhost:9401 to see the Vaadin UI in action:
We’ll continue exploring more topics about UIs with Vaadin Framework and microservices, fault tolerance, and load balancing in the next articles of this series.