Professional Documents
Culture Documents
Medium Com Omarelgabrys Blog Microservices With Spring Boot Creating Our Microserivces Gateway Part 2 31f8aa6b215b
Medium Com Omarelgabrys Blog Microservices With Spring Boot Creating Our Microserivces Gateway Part 2 31f8aa6b215b
OmarElGabry's Blog
. . .
Recalling our application architecture, we have a ser vice registr y, image ser vice,
galler y ser vice, and a gateway.
The galler y ser vice uses the image ser vice underneath, and retrieves a list of all
images to be displayed.
The version of spring boot applications we’re going to create is: 2.0.0.RELEASE.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/>
</parent>
Eureka Server
It’s the naming ser ver, or called ser vice registr y. It’s duty to give names to each
microser vice. Why?
So, ever y ser vice registers itself with Eureka, and pings Eureka ser ver to notify that
it’s alive.
If Eureka ser ver didn’t receive any notification from a ser vice. This ser vice is
unregistered from the Eureka ser ver automatically.
Ok. So, as usual, create a maven project, or use spring initializr. In the pom.xml file,
make sure to include these dependencies: Web, Eureka Ser ver, and DevTools
(optional).
1 ....
2 <dependencies>
3 <dependency>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-starter-web</artifactId>
6 </dependency>
7 <dependency>
8 <groupId>org.springframework.cloud</groupId>
9 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
10 </dependency>
11 <dependency>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-devtools</artifactId>
14 <optional>true</optional>
15 </dependency>
16 </dependencies>
17 ....
Finally, in your spring boot main application class, enable Eureka ser ver using
@EnableEurekaServer annotation.
1 package com.eureka.server;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6
7 @SpringBootApplication
8 @EnableEurekaServer // Enable eureka server
9
10 public class SpringEurekaServerApplication {
11 public static void main(String[] args) {
12 SpringApplication.run(SpringEurekaServerApplication.class, args);
13 }
14 }
So far so good?. Next, we create our ser vices; image and galler y.
Image Service
The Eureka client ser vice is an independent ser vice in a microser vice architecture.
It could be for payment, account, notification, auth, config, etc.
The image ser vice acts as a data source for images, each image has an id, title, and
url. Simple enough?.
Ok. So, for the pom.xml file, instead of Eureka Ser ver, use Eureka Client.
1 ....
2 <dependencies>
3 <dependency>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-starter-web</artifactId>
6 </dependency>
7 <dependency>
8 <groupId>org.springframework.cloud</groupId>
9 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
10 </dependency>
11 <dependency>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-starter-data-rest</artifactId>
14 </dependency>
15 <dependency>
16 <groupId>org.springframework.boot</groupId>
17 <artifactId>spring-boot-devtools</artifactId>
18 <optional>true</optional>
19 </dependency>
20 </dependencies>
21 ....
1 # serivce name
2 spring.application.name=image-service
3 # port
4 server.port=8200
5 # eureka server url
6 eureka.client.service-url.default-zone=http://localhost:8761/eureka
1 package com.eureka.image;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6
7 @SpringBootApplication
8 @EnableEurekaClient // Enable eureka client. It inherits from @EnableDiscoveryClient
9 public class SpringEurekaImageApp {
10 public static void main(String[] args) {
11 SpringApplication.run(SpringEurekaImageApp.class, args);
12 }
13 }
Now, our image ser vice is going to expose some data through endpoints, right?. So,
we need to create a controller, and define the action methods.
1 package com.eureka.image.controllers;
2
3 import java.util.Arrays;
4 import java.util.List;
5
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.core.env.Environment;
8 import org.springframework.web.bind.annotation.RequestMapping;
9 import org.springframework.web.bind.annotation.RestController;
10
11 import com.eureka.image.entities.Image;
12
13 @RestController
14 @RequestMapping("/")
15 public class HomeController {
16 @Autowired
17 private Environment env;
18
19 @RequestMapping("/images")
20 public List<Image> getImages() {
21 List<Image> images = Arrays.asList(
22 new Image(1, "Treehouse of Horror V", "https://www.imdb.com/titl
23 new Image(2, "The Town", "https://www.imdb.com/title/tt0096697/m
24 new Image(3, "The Last Traction Hero", "https://www.imdb.com/tit
25 return images;
26 }
27 }
Don’t forget to create the Image entity class with three fields; id, title, and url.
Gallery Service
The Eureka client ser vice can be also a REST client that calls (consumes) other
ser vices (REST API ser vices) in our microser vice application.
So, for example, the galler y ser vice calls image ser vice to get a list of all images, or
maybe only images created during a specific year.
The calls from this REST client to the other ser vices can be done using:
1. RestTemplate. An object that’s capable of sending requests to REST API ser vices.
What if more than one instance of a service running on different ports. So, we need to
balance the requests among all the instances of a service.
When using ‘Ribbon’ approach (default), requests will be distributed equally among them.
So, as usual, we start by pom.xml . It’s the same as the one for image ser vice. Next is
the application.properties file.
1 spring.application.name=gallery-service
2 server.port=8100
3 eureka.client.service-url.default-zone=http://localhost:8761/eureka
In the spring boot main application class, besides enabling the eureka client, we
need to create a bean for RestTemplate to call the image ser vice.
1 package com.eureka.gallery;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
6 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
7 import org.springframework.context.annotation.Bean;
8 import org.springframework.context.annotation.Configuration;
9 import org.springframework.web.client.RestTemplate;
10
11 @SpringBootApplication
12 @EnableEurekaClient // Enable eureka client.
13 public class SpringEurekaGalleryApp {
14
15 public static void main(String[] args) {
16 SpringApplication.run(SpringEurekaGalleryApp.class, args);
17 }
18 }
19
20 @Configuration
21 class RestTemplateConfig {
22
23 // Create a bean for restTemplate to call services
24 @Bean
25 @LoadBalanced // Load balance between service instances running at dif
26 public RestTemplate restTemplate() {
27 return new RestTemplate();
28 }
29 }
In the controller, call image ser vice using RestTemplate and return the result.
1 package com.eureka.gallery.controllers;
2
3 import java.util.List;
4
5 import org.springframework.beans.factory.annotation.Autowired;
6 import org.springframework.core.env.Environment;
7 import org.springframework.web.bind.annotation.PathVariable;
8 import org.springframework.web.bind.annotation.RequestMapping;
9 import org.springframework.web.bind.annotation.RestController;
10 import org.springframework.web.client.RestTemplate;
11
12 import com.eureka.gallery.entities.Gallery;
13
14 @RestController
15 @RequestMapping("/")
16 public class HomeController {
17 @Autowired
18 private RestTemplate restTemplate;
19
20 @Autowired
21 private Environment env;
22
23 @RequestMapping("/")
24 public String home() {
25 // This is useful for debugging
26 // When having multiple instance of gallery service running at different
27 // We load balance among them, and display which instance received the r
28 return "Hello from Gallery Service running at port: " + env.getProperty(
29 }
30
31 @RequestMapping("/{id}")
32 public Gallery getGallery(@PathVariable final int id) {
33 // create gallery object
34 Gallery gallery = new Gallery();
35 gallery.setId(id);
36
37 // get list of available images
38 List<Object> images = restTemplate.getForObject("http://image-service/im
39 gallery.setImages(images);
40
41 return gallery;
42 }
43
44 // -------- Admin Area --------
45 // This method should only be accessed by users with role of 'admin'
46 // We'll add the logic of role based auth later
47 @RequestMapping("/admin")
48 public String homeAdmin() {
49 return "This is the admin area of Gallery service running at port: " + e
50 }
51 }
Ok, here’s one thing to note. Since we are using restTemplate — which in turn uses
Eureka Server for naming of services, and Ribbon for load balancing. So, we can use the
ser vice name (like image-service ) instead of localhost:port
Gateway — Zuul
When calling any ser vice from the browser, we can’t call it by it’s name as we did
from Galler y ser vice — This is used internally between services.
And as we spin more instances of ser vices, each with a different port numbers, So,
now the question is: How can we call the services from the browser and distribute the
requests among their instances running at different ports?
A gateway is a single entr y point into the system, used to handle requests by routing
them to the corresponding ser vice. It can also be used for authentication,
monitoring, and more.
What’s Zuul?
It’s a proxy, gateway, an intermediate layer between the users and your ser vices.
Eureka ser ver solved the problem of giving names to ser vices instead of hardcoding
their IP addresses.
But, still, we may have more than one ser vice (instances) running on different ports.
So, Zuul …
1. Maps between a prefix path, say /gallery/** and a ser vice gallery-service . It
uses Eureka ser ver to route the requested ser vice.
1 ....
2 <dependencies>
3 <dependency>
4 <groupId>org.springframework.boot</groupId>
5 <artifactId>spring-boot-starter-web</artifactId>
6 </dependency>
7 <dependency>
8 <groupId>org.springframework.cloud</groupId>
9 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
10 </dependency>
11 <dependency>
12 <groupId>org.springframework.cloud</groupId>
13 <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
14 </dependency>
15 <dependency>
16 <groupId>org.springframework.boot</groupId>
17 <artifactId>spring-boot-devtools</artifactId>
18 <optional>true</optional>
19 </dependency>
20 </dependencies>
21 ....
It’s worth mentioning that Zuul acts as a Eureka client. So, we give it a name, port, and
link to Eureka server (same as we did with image service).
1 server.port=8762
2 spring.application.name=zuul-server
3 eureka.client.service-url.default-zone=http://localhost:8761/eureka/
4
5 # A prefix that can added to beginning of all requests.
6 #zuul.prefix=/api
7
8 # Disable accessing services using service name (i.e. gallery-service).
9 # They should be only accessed through the path defined below.
10 zuul.ignored-services=*
11
12 # Map paths to services
13 zuul.routes.gallery-service.path=/gallery/**
14 zuul.routes.gallery-service.service-id=gallery-service
15
1 package com.eureka.zuul;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6 import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
7
8 @SpringBootApplication
9 @EnableEurekaClient // It acts as a eureka client
10 @EnableZuulProxy // Enable Zuul
11
12 public class SpringZuulApplication {
13
14 public static void main(String[] args) {
15 SpringApplication.run(SpringZuulApplication.class, args);
16 }
17 }
To test our application, run eureka ser ver, zuul, and then the two ser vices. Then, go
to Eureka Ser ver running at localhost:8761 , you should see the running ser vices.
To ping the galler y ser vice, send a request to the gateway, adding the path for the
galley ser vice localhost:8762/gallery .
You should see the below message, and if you hit the url again, the request will be
routed to the second instance of galler y ser vice; thanks to the load balancer.
{
"id": 1,
"images": [
{
"id": 1,
"title": "Treehouse of Horror V",
"url": "https://.../rm3842005760"
},
{
"id": 2,
"title": "The Town",
"url": "https://.../rm3698134272"
},
{
"id": 3,
"title": "The Last Traction Hero",
"url": "https://.../rm1445594112"
}
]
}
But, we aren’t done yet!. We still have to authenticate the users. Next, we’ll use JSON
Web Tokens (JWT) for authentication.
. . .
3.3K claps
WRIT T EN BY
OMAR ELGABRY
Follow
OmarElGabry's Blog
Follow
Plug-in Architecture
OMAR ELGABRY in OmarElGabry's Blog
May 1, 2019 · 9 min read 701
Threads Vs Queues
OMAR ELGABRY in OmarElGabry's Blog
Apr 15, 2019 · 11 min read 574
Related reads