Core Business – Statement Service and CardStatementComposite

Before we start

If you hit this page without following the Step-by-step into Micro-Services Architecture with Spring and Netflix OSS, it can be useful to know about the serie:

Info: It is highly recommended to follow the part 4.1 before you start here. Notwithstanding, some steps / explanations will be omitted, since they are already explained there – hence, at your own risk 😉

Part 4.2

Statement Service

We broadly did it until now, so that, the steps are summarized here to save your reading time.

http://start.spring.io

Create a new project:

Generate a: Maven Project
Spring Boot: 1.3.3
Group: com.spring.netflix.oss.microservices
Artifact: statement-service
Dependencies:
Actuator, Web, Config Client, Eureka Discovery
Screenshot from 2016-04-02 18:40:33

After this, import into your IDE.

Edit the class StatementServiceApplication adding @EnableEurekaClient.

Remove the file application.properties from src/main/resources and add a new file under the same path, called: bootstrap.yml. Here its content:

spring:
  application:
    name: statement-service
  cloud:
    config:
       uri: http://localhost:9090

Create a package called: model under com.spring.netflix.oss.microservices.

Screenshot from 2016-04-11 19:58:54

There, create a class named Statement:

package com.spring.netflix.oss.microservices.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class Statement {
	private Long id;
	private Long cardId;
	private String operationDate;
	private String value;
	
	public Statement() {
		super();
	}
	
	public Statement(Long id, Long cardId, String operationDate, String value) {
		super();
		this.id = id;
		this.cardId = cardId;
		this.operationDate = operationDate;
		this.value = value;
	}

	public Long getCardId() {
		return cardId;
	}

	public void setCardId(Long cardId) {
		this.cardId = cardId;
	}

	public String getOperationDate() {
		return operationDate;
	}

	public void setOperationDate(String operationDate) {
		this.operationDate = operationDate;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return "Statement [id=" + id + ", cardId=" + cardId + ", operationDate=" + operationDate + ", value=" + value
				+ "]";
	}

}

The same step as we did for card-service – let’s expose an API. One more package, api, also under com.spring.netflix.oss.microservices.

In this package, also create a class named: StatementServiceController.

Screenshot from 2016-04-11 20:17:53

The code for this comes here:

package com.spring.netflix.oss.microservices.api;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.spring.netflix.oss.microservices.model.Statement;

@RestController
@RequestMapping(value="/api")
public class StatementServiceController {
	
	private List<Statement> fakeRepo;
	
	@PostConstruct
	public void init(){
		this.fakeRepo = new ArrayList<>();
		fakeRepo.add(new Statement(1l, 2l,"01/11/15 08:41", "US$411.05"));
		fakeRepo.add(new Statement(2l, 1l,"13/04/13 20:16", "US$1,914.00"));
		fakeRepo.add(new Statement(3l, 3l,"31/12/15 18:00", "€12.10"));
		fakeRepo.add(new Statement(4l, 4l,"21/11/10 19:55", "US$1.50"));
		fakeRepo.add(new Statement(5l, 4l,"10/06/14 09:37", "US$116.00"));
		fakeRepo.add(new Statement(6l, 5l,"14/01/12 14:49", "R$11.02"));
		fakeRepo.add(new Statement(7l, 7l,"15/12/20 12:00", "US$14.60"));
		fakeRepo.add(new Statement(9l, 6l,"01/11/09 13:02", "€1,888.93"));
		fakeRepo.add(new Statement(10l, 6l,"01/11/20 08:41", "€293.30"));
		fakeRepo.add(new Statement(11l, 6l,"01/11/20 08:41", "€11.68"));
	}


	@RequestMapping(value="/statements", method = RequestMethod.GET)
	public List<Statement> getStatements() {
		return fakeRepo;
	}
	
	@RequestMapping(value="/statement/{statementId}", method = RequestMethod.GET)
	public Statement getStatament(@PathVariable Long statementId) {
		return Optional.ofNullable(
				fakeRepo
				.stream()
				.filter((statement) -> statement.getId().equals(statementId))
                .reduce(null, (u, v) -> {
                    if (u != null && v != null)
                        throw new IllegalStateException("More than one StatementId found");
                    else return u == null ? v : u;
                })).get();
		
	}
	
	@RequestMapping(value="/statement", method = RequestMethod.GET)
	public List<Statement> getStatements(@RequestParam Long cardId){
		if(cardId!=null){
			return fakeRepo
					.stream()
					.filter((statement) -> statement.getCardId().equals(cardId))
					.collect(Collectors.toList());
		}
		return null;
	}

}

Navigate until our config folder path, i.e. ~/dev/workspace/spring-netflix-oss-microservices/microservices-config/MASTER and create a new file called statement-service.yml. Its he code:

server:
  port: 0

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Commit and push to our configuration project.
If you are following the series from the beginning, you might be thinking: “Why did we set up the server.port on that way (with zero)?

The answer for this question is pretty simple – until now, even for test what we’ve created, we are always calling in specific server / ports, in spite of that, it is NOT the smartest way to deal with this kind of architecture.

Being honest, in fact our project until now is kind of useless for our main purpose. From now, we’re starting to use some features that we have enabled but are currently underused. For the sake of this abstraction of ports that we want to achieve, we need to change some configurations that we did in a previous part of the series.

Edit the config file card-service.yml and also set the port to 0 (zero). Later, open a class called EdgeServerApplication.java and we’ll change an annotation @EnableZuulServer for @EnableZuulProxy. With this, we’re asking to our Edge-Server to act as a reverse proxy – some step ahead we’ll set up the routes for this.

Excellent! Now we have one more service ready.

Part 4.3

Card Statement Composite

When you read the term Composite, you must be probably thinking in the litteracy meaning of this word. According to thefreedictionary.com:
a. Made up of distinct components; compound.

If you do so, yes, well done – the meaning is exactly we want to achieve here. According to Magnus Larsson on his article about Microservices:

Composite services Composite services can either orchestrate a number of core services to perform a common task or aggregating information from a number of core services.

Said that, in our example, the purpose to create a composite is just to leave the card and statement module a little bit more independent, it is, each one take care just its own concerns.

One more project is required:

Screenshot from 2016-04-11 22:13:27

Generate a: Maven Project
Spring Boot: 1.3.3
Group: com.spring.netflix.oss.microservices
Artifact: card-statement-composite
Dependencies:
Actuator, Web, Config Client, Eureka Discovery and Feign

Feign is the only Spring / Netflix tool new here, its function is to transform what we would do via httpClient or RestTemplate in a easier task. From its website:

How does Feign work?

Feign works by processing annotations into a templatized request. Just before sending it off, arguments are applied to these templates in a straightforward fashion. While this limits Feign to only supporting text-based apis, it dramatically simplified system aspects such as replaying requests. It is also stupid easy to unit test your conversions knowing this.

As soon as we start to write our code, we are going to see about it.

By now, this couple of things that we are doing at this stage kind of automatically.

Import into your IDE.

Edit the class CardStatementCompositeApplication adding @EnableEurekaClient. But that is not all for here, we need also to add @EnableFeignClients. The final class will be:

package com.spring.netflix.oss.microservices;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class CardStatementCompositeApplication {

	public static void main(String[] args) {
		SpringApplication.run(CardStatementCompositeApplication.class, args);
	}
}

Inside src/main/resources delete all folders and files and recreate a new one called bootstrap.yml, with content equals:

spring:
  application:
    name: card-statement-composite
  cloud:
    config:
      uri: http://localhost:9090

One more setup step – inside our microservice-config/MASTER, we’ll create a file named card-statement-composite.yml, the content:

server:
port: 0

eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
Info: The watchful probably realized that this config is the same ostatement-service. Spring cloud config has a nice inheritance feature that allows us to avoid extensive configuration – later we’ll fix it to take advantage of this feature.

Now, the code that really uses Feign client and that “compound” our separate modules in something that makes sense.

Screenshot from 2016-04-14 21:56:27

In which we’ll create 2 different classes – CardVO and StatementVO, respectively:

CardVO

package com.spring.netflix.oss.microservices.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class CardVO {

	private Long id;
	private String cardHolderName;
	private String pan;
	private String validDate;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getCardHolderName() {
		return cardHolderName;
	}
	public void setCardHolderName(String cardHolderName) {
		this.cardHolderName = cardHolderName;
	}
	public String getPan() {
		return pan;
	}
	public void setPan(String pan) {
		this.pan = pan;
	}
	public String getValidDate() {
		return validDate;
	}
	public void setValidDate(String validDate) {
		this.validDate = validDate;
	}
	@Override
	public String toString() {
		return "CardVO [id=" + id + ", cardHolderName=" + cardHolderName + ", pan=" + pan + ", validDate=" + validDate
				+ "]";
	}
}

 

StatamentVO

package com.spring.netflix.oss.microservices.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown=true)
public class StatementVO {
	private Long id;
	private Long cardId;
	private String operationDate;
	private String value;
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public Long getCardId() {
		return cardId;
	}
	public void setCardId(Long cardId) {
		this.cardId = cardId;
	}
	public String getOperationDate() {
		return operationDate;
	}
	public void setOperationDate(String operationDate) {
		this.operationDate = operationDate;
	}
	
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	@Override
	public String toString() {
		return "StatementVO [id=" + id + ", cardId=" + cardId + ", operationDate=" + operationDate + ", value=" + value
				+ "]";
	}
	
}

Following: another package

Screenshot from 2016-04-14 22:04:50

Inside this, we are going to manage our services and Feign Client will do the magic to call the other modules for us. Lets create 4 different interfaces – the code will talk by itself and will be easy to comprehend what they meaning.

    1. CardService
package com.spring.netflix.oss.microservices.service;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.spring.netflix.oss.microservices.model.CardVO;

public interface CardService {
	final static String PREFIX = "api/";
	
	@RequestMapping(value = PREFIX + "cards", method = GET)
	List<CardVO> getCards();
	
	@RequestMapping(value = PREFIX + "card/{cardId}", method = GET)
	CardVO getCard(@PathVariable("cardId") Long cardId);
	
	@RequestMapping(value= PREFIX + "new-card", method = POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) //it could be PUT
	void createCard(@RequestBody CardVO card);
	
}
    1. CardClient
package com.spring.netflix.oss.microservices.service;

import org.springframework.cloud.netflix.feign.FeignClient;

@FeignClient(name = "card-service")
public interface CardClient extends CardService{

}
    1. StatementService
package com.spring.netflix.oss.microservices.service;

import static org.springframework.web.bind.annotation.RequestMethod.GET;

import java.util.List;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.spring.netflix.oss.microservices.model.StatementVO;

public interface StatementService {
	
final static String PREFIX = "api/";
	
	@RequestMapping(value = PREFIX + "statements", method = GET)
	List<StatementVO> getStatements();
	
	@RequestMapping(value = PREFIX + "statement/{statementId}", method = GET)
	StatementVO getStatament(@PathVariable("statementId") Long statementId);
	
	@RequestMapping(value= PREFIX + "statement", method = GET)
	List<StatementVO> getStatements(@RequestParam("cardId") Long cardId);

}

    1. StatementClient
package com.spring.netflix.oss.microservices.service;

import org.springframework.cloud.netflix.feign.FeignClient;

@FeignClient(name = "statement-service")
public interface StatementClient extends StatementService{

}

 As you saw, we are preparing to consume our API that we designed for Card and Statement. At this point, is very important to pay attention to exposed names (once the module has to match with Feign), attributes, path variables and every detail. Be sure that all is correct, otherwise you’ll have a headache to find the problem – it is a personal opinion, but I think that is annoying to find a error detail in a vast API.

Well, once the Feign clients are create, lets make use of them. Now, one class in the same package – CardStatementServiceController.java, the code:

package com.spring.netflix.oss.microservices.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.spring.netflix.oss.microservices.model.CardVO;
import com.spring.netflix.oss.microservices.model.StatementVO;

@RestController
@RequestMapping("/api")
public class CardStatementServiceController {

	@Autowired
	CardClient cardClient;
	
	@Autowired
	StatementClient statementClient;
	
	@RequestMapping(value="/statement-by-card", method=RequestMethod.GET)
	public ResponseEntity<Map<CardVO, List<StatementVO>>> 
	getStatementByCardId(@RequestParam Long cardId){
		Map<CardVO, List<StatementVO>> response = new HashMap<>();
		
		response.put(cardClient.getCard(cardId), statementClient.getStatements(cardId));
		
		return new ResponseEntity<Map<CardVO,List<StatementVO>>>(response, HttpStatus.OK);
	}
}

 Repair that we just injected our clients here and, from them, we are invoking our service without many worries. By the way, in new versions of Feign we have possibility to define a fallback method case our clients failed. We won’t do it now because this tutorial is getting very big.

The last thing, I promise. We transformed our Edge-Server in a reverse proxy, so, as aforementioned, it is required to edit edge-server.yml to create our rotes. At the end of the day, this file must be exactly this:

server:
  port: 8765

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

zuul:
  debug:
    request: true
  routes:
    card-service:
        path: /card-service/**
        serviceId: card-service
        stripPrefix: true
    statement-service:
        path: /statement-service/**
        serviceId: statement-service
        stripPrefix: true
    card-statement-composite:
        path: /card-statement-composite/**
        serviceId: card-statement-composite
        stripPrefix: true

 Don’t forget to commit your configuration, push it to remote and later start the server in this sequence:

  1. Config-Server
  2. Discovery-Service
  3. {Edge-Server, Card-Service, Statement-Server and Card-Statement-Composite}

See that  where we left without a port defined, the Spring set a random for us and the discovery is in charge, lets say, to discovery it. :O

Screenshot from 2016-04-18 23:22:00

To access and see the results, all that we must to do is:

http://localhost:8765/card-statement-composite/api/statement-by-card?cardId=4

Now we hit the Edge-Server, it does the proxy for us. On the other hand, Feign client present on card-statement-composite is invoking the card-service and statement-service.

Our pretty basic expected result is showed below.

Screenshot from 2016-04-18 23:28:01

Well, we did much work by today, see you in our next blog post.

Config-Server & Discovery Service

Part 2.

 

If you hit this page without following the Step-by-step into Micro-Services Architecture with Spring and Netflix OSS, I strongly recommend you to read the following links:

What is a Config-Server?

Before dig into the micro-services in a literacy way (let’s say: the core of our application, that will keep our business rules) we need a centralized and straightforward manner to configure and retrieve the configurations about all the services that we’re supposing to develop. It’s also important because when we do this kind of “abstraction”, I mean – a centralized way to rule all configs, we are not carrying the burden of remembering where each configuration are distributed across multiple and distributed components.

Another advantage of keeping these configurations apart is, according to the official Spring’s web site (http://cloud.spring.io/spring-cloud-config/):

As an application moves through the deployment pipeline from dev to test and into production you can manage the configuration between those environments and be certain that applications have everything they need to run when they migrate.

So far, we are  talking about an external way to manage this configuration, but, for those who are thinking “where could be a good place to keep this important files?”, for this step-by-step I’ll suggest git (if you are not familiar with git, it’s a good time to start learning – trust me, soon or later you will need it).

git

 

Hands-on

First of all, we must initiate an empty repository that will keep our code organised.

Properly logged on Github.com, just access:

https://github.com/new

Fill the available options in this way:

 Repository Name: spring-netflix-oss-microservices

Description: Our microservice architecture parent project

Check the Public option

Initialize this repository with a README

And click -> Create a Repository button

Screenshot from 2016-03-20 09:11:37

Once you create, you will see a Github page like this:

Screenshot from 2016-03-20 09:14:53

Copy the URL from HTTPS text box, go until your favourite cmd, navigate until your workspace path and do a clone of this project. Example:

fernando@fernando-Vostro-5470:~$ cd ~/dev/workspace/
fernando@fernando-Vostro-5470:~/dev/workspace/$ git clone https://github.com/fernandoabcampos/spring-netflix-oss-microservices.git
Cloning into 'spring-netflix-oss-microservices'...
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
Checking connectivity... done.

Attention for this command:

git clone https://github.com/fernandoabcampos/spring-netflix-oss-microservices.git
Obviously with the https url that you copied from your github.

It does the “magic” for us.

For now, leave this project empty and soon we’ll use it again.

Given this very beginner introduction, let’s start the good part – work with Spring. There are some ways to create a Spring Boot application. We’ll create through the easiest one (website), but let’s show another for the command line guys 😉

It is pretty simple, on you command line just type:

curl start.spring.io

It’s possible that you don’t have CURL installed on your machine – follow the instructions according to your O.S. to have it installed whether you want do in the command line way.

The result that you’ll see is, in short, something like this:

$ curl start.spring.io


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 
:: Spring Initializr ::  https://start.spring.io
...

By the end there are some explanations about how to create each kind of project – if you curious about, you can see the full return of this curl command here.

Return to what I consider the easiest way to create a Spring Boot project, access:

http://start.spring.io/

For this example, although particularly I have a thing for Gradle, let’s select:

  • Generate a: Maven Project
  • Spring Boot: 1.3.2
  • Project Metadata:
    • Group: com.spring-netflix-oss.microservices
    • Artifact: config-server
  • Dependencies
    • Config Server
    • Actuator

By the end, your set-up will be like this:

Screenshot from 2016-02-24 22:39:39

As soon as you click at “Generate Project” the download will start automatically and a zip file with the name config-server.zip will be delivered to you.

Unzip it into your project path – for whom those are not familiar with this, I like to keep my projects under ~/dev/workspace, so the pwd of our unzip would be ~/dev/workspace/spring-netflix-oss-microservices/config-server.

Info:  It’s a particular decision, but it’s recommended to do so – the following modules will play easily if we keep our code organised.

 

Inside your IDE

File / Import …

Screenshot from 2016-03-17 21:26:23

Choose: Existing Maven Project

As the option Select Root Directory: ~/dev/workspace/spring-netflix-oss-microservices/config-server
Project: pom.xml from our config-server

Screenshot from 2016-03-16 22:33:17

Finish.

Our project will be imported into our IDE and we are now ready to start.

We’ll create an application.yml file that mainly is responsible for dictating some important points, for instance, the server port that this server will run and also for where our server will look up when finding configs.

To do so, under Package Explorer, select the src/main/resources folder, right click, New -> File.

Now create a file named as: application.yml

Screenshot from 2016-03-20 08:52:16.png

We’ll fill this file later.

At the same place, there is another file called application.properties, you can select and delete it because we won’t use (once that application.yml do the same for us).

Screenshot from 2016-03-16 22:41:31

Lastly, at the same path, create a bootstrap.yml file that will allow us to determine a name of our module. The content of this file is just:

spring:
    application:
        name: config-server

It was aforementioned that we’ll use git for managing our config project, so, without further ado, let’s create another repository:

Properly logged on Github.com again, just access:

https://github.com/new

Set-up your new repository as follows:

Screenshot from 2016-03-16 22:47:24

And create your repo.

Once you finished, you will have something like this:

Screenshot from 2016-03-16 22:53:35

Copy the text box, labeled here as HTTPS, with the URL from your project that you just create. Go until your favourite cmd, navigate until your workspace / project path and do a clone of this project. Example:

fernando@fernando-Vostro-5470:~$ cd ~/dev/workspace/spring-netflix-oss-microservices/
fernando@fernando-Vostro-5470:~/dev/workspace/spring-netflix-oss-microservices$ git clone https://github.com/fernandoabcampos/microservices-config.git
Cloning into 'microservices-config'...
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
Checking connectivity... done.

 

Attention for this command:

git clone https://github.com/fernandoabcampos/microservices-config.git
Obviously with the https url that you copied from your github.


As the tutorial moves on, you will realize for what this project was created. By now, that is all we need.

Returning to the Config-Server, we need to say to Spring that this project is a Config Server. We do this by adding @EnableConfigServer in our main class, i.e. ConfigServerApplication under

src/main/java/com.spring.netflix.oss.microservices.ConfigServerApplication

See the code:

package com.spring.netflix.oss.microservices;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ConfigServerApplication.class, args);
	}
}

 

One more stuff to do is to edit the application.yml that we created some steps ago. There we’ll add some important informations about the location of our config-server. Edit it and add (don’t forget to substitute the uri for your own repository):

# Defines the port where the config server is running so that rest of the services can pick up
# their external configurations
server:
    port: 9090 

spring:
    cloud:
        config:
            server:
                git:
                    uri: https://github.com/fernandoabcampos/microservices-config.git
                    searchPaths: MASTER

 

With this simple configuration we are saying to Spring that we want to run at 9090 Port, and the rest of the configuration will be found at our GitHub repo. Note that we defined a specific searchPaths. It is what we are going to create now. It is easy -> inside your microservice-config folder, just create an empty folder called MASTER. Latter will push all of this to Github and the configuration above will be Ok.

Screenshot from 2016-03-20 10:57:57

 

Wow, take a deep breath.

Discovery Service

Well, we did a scaffold of our config-server – there is some steps over it that appear in some minutes. Nevertheless, if we want to build a really distributed microservices architecture, we will need to have a mechanism that allow us to register new instances of our services automatically (be them support services or core services), i.e., once the microservice is up, this mechanism will help through a self-register and keep a tracking of the ports, for example.
It is substantial because we need to build a scalable, resilient and fault-tolerant system. Without this mechanism, we would have to maintain a list of ports, servers and be aware of all systems ongoing.

For this purpose, we choose the Netflix Eureka. Suggestive name, no?

What is Eureka? (according to its own documentation)

Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers. We call this service, the Eureka Server. Eureka also comes with a Java-based client component,the Eureka Client, which makes interactions with the service much easier. The client also has a built-in load balancer that does basic round-robin load balancing. At Netflix, a much more sophisticated load balancer wraps Eureka to provide weighted load balancing based on several factors like traffic, resource usage, error conditions etc to provide superior resiliency.

Given this, we know that we’ll have two kind of Eureka Components – the Eureka Server and the Eureka Clients. Let’s do the first of them:

Screenshot from 2016-03-20 11:45:43

The procedure is the same than other services that we already build.
Visit http://start.spring.io, create your project as the image above and import into IDE.

Without wasting our time, edit the class DiscoveryServiceApplication and add @EnableEurekaServer.

package com.spring.netflix.oss.microservices;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(DiscoveryServiceApplication.class, args);
    }
}

 

After this, in src/main/resources, delete application.properties that must be present there and create a new File called bootstrap.yml. The purpose of this file is to define a name for this sub-project and to set-up the configuration server for which the application will look at.

Created the file, add the following info inside it:

spring:
    application:
        name: discovery-service
    cloud:
        config:
            uri: http://localhost:9090

Easy peasy! Note that we are pointing to 9090 port. It isn’t random – we sure are point to configuration-server that we just created steps ago.

Almost done… The next step is to create a file called discovery-service.yml under:

/dev/workspace/spring-netflix-oss-microservices/microservices-config/MASTER

The content of this file is:

server:
    port: 8761

# Defines the Eureka server that is used by the Netflix OSS components to use as the registry
# for server discovery
eureka:
    instance:
        hostname: localhost
        leaseRenewalIntervalInSeconds: 5
    client:
        registerWithEureka: false
        fetchRegistry: false
        serviceUrl:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

 

The configuration is ready, do a push for your remote repository (otherwise when we try to start our config-server, it will not find the appropriate PATH: MASTER that we just put.

fernando@fernando-Vostro-5470:~$ cd /dev/workspace/spring-netflix-oss-microservices/microservices-config/
fernando@fernando-Vostro-5470:~/dev/workspace/spring-netflix-oss-microservices$ git push origin master
...

 

Ok, the files are remote and up-to-date now.

Finally, we can run our application. On Boot Dashboard panel, select the config-server and run. Later, do the same with discovery-service.

Screenshot from 2016-03-20 12:29:39

Well, too much for while.

The next step is to build a gatekeeper (Zuul Proxy); fault tolerance logic (hystrix); monitor dashboards, the core services themselves.

I hope this tutorial can be useful for your.

 

See you soon with the next part.