-
Notifications
You must be signed in to change notification settings - Fork 59
Spring Cloud Zuul
Source Folder: netflix-zuul
Tech Stack:
- spring-boot
- spring-mvc
- netflix-zuul
- netflix-eureka
- log4j2 (slf4j impl)
- project lombok
This is a ready-to-use Maven Java project template with the libraries listed above.
In a microservices architecture it is typical to have many system components independent of each other. This brings problems like:
- UI developers need to know the addresses of each microservice they need to consume
- CORS - Cross Origin Resource Sharing
- Multiple Authentication
Zuul is used as an API gateway which receives all requests from the users and calls corresponding underlying microservices based on the configurations. With this architecture:
- we won't have CORS issues
- we will have centralized security implementation which will be applied to all incoming requests.
- we can apply filters to all incoming requests
- when needed we will be able to change the security and filter implementations easily (since they are centralized)
- API gateway will be another microservice meaning that it will be scalable
In this solution I will create:
- eureka-server : The service registry
- customer-service: A microservice that gives information about customers.
- zuul-proxy: The API gateway
In short, the clients will make requests to zuul proxy. The zuul proxy will redirect the request to corresponding microservice and return the result.
In this example:
- customer-service is implemented with eureka-client (it is registered to the service registry on startup)
- zuul-proxy is integrated with eureka so that it can find underlying services with their names (instead of direct URLs)
dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
configuration
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
The entry point:
@EnableEurekaServer
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
The customer service is a simple Spring Boot application. The only difference is that the eureka-client is enabled. It registers itself to the service registry on startup.
dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
configuration:
server:
port: 8090
spring:
application:
name: customer-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
instance:
preferIpAddress: true
The entry point:
@EnableDiscoveryClient
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
The customer model:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private String id;
private String name;
private String company;
private LocalDate birthdate;
}
The customer list resource:
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@GetMapping
public List<Customer> customerList() {
Customer c1 = Customer.builder()
.id("1").name("john doe").company("acme").birthdate(LocalDate.now().minusYears(28)).build();
Customer c2 = Customer.builder()
.id("2").name("jane doe").company("acme").birthdate(LocalDate.now().minusYears(24)).build();
List<Customer> result = new ArrayList<>();
result.add(c1);
result.add(c2);
return result;
}
}
You can run and test your customer service right now. You should be able to access the customer list resource with the http://localhost:8090/api/customers URL
Now, it is time to enable the Zuul Proxy
dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
configuration:
server:
port: 8080
spring:
application:
name: zuul-proxy
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
instance:
preferIpAddress: true
zuul:
routes:
customer-service:
serviceId: customer-service
host:
socket-timeout-millis: 30000
The entry point:
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
Now we are ready. Make sure that all three applications are running and then you can test your zuul proxy.
- Send request to the zuul proxy:
http://localhost:8080/customer-service/api/customers. - The zuul proxy will redirect the request to
customer-service/api/customersand with eureka service registry, it can resolve the exact path of thecustomer-service - You should be able to get the customer list response:
[
{
"id": "1",
"name": "john doe",
"company": "acme",
"birthdate": "1990-10-08"
},
{
"id": "2",
"name": "jane doe",
"company": "acme",
"birthdate": "1994-10-08"
}
]
Zuul uses Netflix Ribbon to discover all the instances of a service from the Eureka Service Discovery Server. It automatically finds the physical locations of each service instance and redirects the requests to the actual services holding the resources to be accessed.
You can test it for yourself. Just add some logs into the customerList handler method and start multiple instances of the customer service. Call the http://localhost:8080/customer-service/api/customers URL multiple times and see the logs of each instance to understand which one is called on each request.
Because Zuul can add, change, and compile filters at run-time, system behavior can be quickly altered. We add new routes, assign authorization access rules, and categorize routes all by adding or modifying filters. And when unexpected conditions arise, Zuul has the ability to quickly intercept requests so we can explore, workaround, or fix the problem.
The dynamic filtering capability of Zuul allows us to find and isolate problems that would normally be difficult to locate among our large volume of requests. A filter can be written to route a specific customer or device to a separate API cluster for debugging.
Sample scenarios where Zuul filters can be used:
- logging
- routing
- ddos prevention
- reverse proxying
- Home
- JPA Specification
- JMS with Spring Boot
- JMS with Spring Boot & Apache Camel
- Caching with Spring Boot & Redis
- Netflix Eureka with Spring Boot
- Netflix Hystrix & Eureka with Redis Cache
- Netflix Zuul
- Authentication Types
- Separating Unit & Integration Tests Execution Phases with Maven
- Basic CSRF Attack Simulation & Protection
- Spring Batch
- Dagger
- Concurrency with Java
- Swagger2 with Spring Boot