Spring Cloud Gateway
Spring Cloud Gateway provides a library for building API gateways on top of Spring and Java. It provides a flexible way of routing requests based on a number of criteria, as well as focuses on cross-cutting concerns such as security, resiliency, and monitoring. An API gateway allows you to implement the complexity separately from the client, moving that responsibility from user side to server side. All the client needs to know is how to talk to the gateway. It doesn’t matter whether the backend services run, go offline, or become unstable as long as the gateway knows how to handle these situations.
Spring Cloud Gateway Architecture
- Route: Route is the basic building block of the gateway. It consists of
- ID
- destination URI
- Collection of predicates and a collection of filters
- A Route is matched if the aggregate’s predicate is true.
- Predicate: It is similar to Java 8 Function Predicate. Using this functionality we can match HTTP request, such as headers , url, cookies or parameters.
- Filter: These are instances of Spring Framework GatewayFilter. Using this we can modify the request or response as per the requirement.
Implement Student Microservice
Maven project will be like this
The pom.xml will be as follows-
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.javainuse</groupId>
<artifactId>student-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>
Define the application.yml as follows
spring:
application:
name: student-service
server:
port: 8081
Create the bootstrap class(StudentApplication) with the @SpringBootApplication annotation
package com.springmicroservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudentApplication {
public static void main(String[] args) {
SpringApplication.run(StudentApplication.class, args);
}
}
Create a Controller class that exposes the GET REST service as follows
package com.springmicroservice.controller;
import org.json.simple.JSONObject;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/student")
public class StudentController {
@GetMapping("/records")
public JSONObject test() {
JSONObject obj=new JSONObject();
obj.put("subject_code","Math");
obj.put("dept_name","CSE");
obj.put("name","Sumit");
obj.put("id",new Integer(101));
System.out.println("Student Service Invoked...");
return obj;
}
}
Implement Subject Microservice
Maven project will be like this
The pom.xml will be as follows-
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.javainuse</groupId>
<artifactId>subject-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>
Define the application.properties as follows
spring:
application:
name: subject-service
server:
port: 8082
Create the bootstrap class(SubjectApplication) with the @SpringBootApplication annotation
package com.springmicroservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SubjectApplication {
public static void main(String[] args) {
SpringApplication.run(SubjectApplication.class, args);
}
}
Create a Controller class that exposes the GET REST service as follows-
package com.springmicroservice.controller;
import org.json.simple.JSONObject;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/subject")
public class SubjectController {
@GetMapping("/records")
public JSONObject test() {
JSONObject obj=new JSONObject();
obj.put("code","Math");
obj.put("name","Mathematics");
obj.put("subjectId",new Integer(101));
System.out.println("Subject Service Invoked...");
return obj;
}
}
Implement Spring Cloud Gateway using property based config
The pom.xml will be as follows
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javainuse</groupId>
<artifactId>cloud-gateway-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-service</name>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Create the bootstrap class(APIGatewayApplication) with the @SpringBootApplication annotation
package com.springcloudgateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import reactor.core.publisher.Mono;
@SpringBootApplication
public class APIGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(APIGatewayApplication.class, args);
}
}
To make Custom filters we need to inherit AbstractGatewayFilterFactory class.
package com.springcloudgateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
@Component
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
System.out.println("First pre filter" + exchange.getRequest());
//Custom Post Filter.Suppose we can call error response handler based on error code.
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
System.out.println("First post filter");
}));
};
}
public static class Config {
// Put the configuration properties
}
}
Specify the Custom Filter in the route in application.yml file
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: studentModule
uri: http://localhost:8081/
predicates:
- Path=/student/**
filters:
- CustomFilter
- id: subjectModule
uri: http://localhost:8082/
predicates:
- Path=/subject/**
filters:
- CustomFilter
Start the applications-
- cloud-gateway-service
- student-service
- subject-service
Run the application.
- Go to browser and type localhost:8080/student/records –
In the browser we can see that the post filter has been applied to response.
Go to browser and type localhost:8080/subject/records
In the browser we can see that the post filter has been applied to response.
Conclusion
In this blog, we have covered how to implement and configure Custom Filter to Spring Cloud Gateway Service. Now you are ready to go to implement Custom Filter to Spring Cloud gateway. For more, you can refer to the documentation: https://cloud.spring.io/spring-cloud-gateway/reference/html/