In a distributed architecture like a microservices one, there will come a point where you’ll need to ensure that key behaviors such as security, logging, and tracking of users across multiple service calls occur. To implement this functionality, you’ll want these attributes to be consistently enforced across all of your services without the need for each individual development team to build their own solutions. While it’s possible to use a common library or framework to assist with building these capabilities directly in an individual service, doing so has three implications.
First, it’s difficult to consistently implement these capabilities in each service being built. Developers are focused on delivering functionality, and in the whirlwind of day-to-day activity they can easily forget to implement service logging or tracking. (I personally am guilty of this.) Unfortunately, for those of us working in a heavily regulated industry, such as financial services or healthcare, showing consistent and documented behavior in your systems is often a key requirement for complying with government regulations.
Second, properly implementing these capabilities is a challenge. Things like microservice security can be a pain to set up and configure with each service being implemented. Pushing the responsibilities to implement a cross-cutting concern like security down to the individual development teams greatly increases the odds that someone will not implement it properly or will forget to do it.
Third, you’ve now created a hard dependency across all your services. The more capabilities you build into a common framework shared across all your services, the more difficult it is to change or add behavior in your common code without having to recompile and redeploy all your services. This might not seem like a big deal when you have six microservices in your application, but it’s a big deal when you have a larger number of services, perhaps 30 or more. Suddenly an upgrade of core capabilities built into a shared library becomes a months-long migration process.
To solve this problem, you need to abstract these cross-cutting concerns into a service that can sit independently and act as a filter and router for all the microservice calls in your application. This cross-cutting concern is called a services gateway. Your service clients no longer directly call a service. Instead, all calls are routed through the service gateway, which acts as a single Policy Enforcement Point (PEP), and are then routed to a final destination.
In this chapter, we’re going to see how to use Spring Cloud and Netflix’s Zuul to implement a services gateway. Zuul is Netflix’s open source services gateway implementation. Specifically, we’re going to look at how to use Spring Cloud and Zuul to
Let’s dive into more detail on how a services gateway fits into the overall microservices being built in this book.
Until now, with the microservices you’ve built in earlier chapters, you’ve either directly called the individual services through a web client or called them programmatically via a service discovery engine such as Eureka.

A service gateway acts as an intermediary between the service client and a service being invoked. The service client talks only to a single URL managed by the service gateway. The service gateway pulls apart the path coming in from the service client call and determines what service the service client is trying to invoke. Figure 6.2 illustrates how like a “traffic” cop directing traffic, the service gateway directs the user to a target microservice and corresponding instance. The service gateway sits as the gatekeeper for all inbound traffic to microservice calls within your application. With a service gateway in place, your service clients never directly call the URL of an individual service, but instead place all calls to the service gateway.

Because a service gateway sits between all calls from the client to the individual services, it also acts as a central Policy Enforcement Point (PEP) for service calls. The use of a centralized PEP means that cross-cutting service concerns can be implemented in a single place without the individual development teams having to implement these concerns. Examples of cross-cutting concerns that can be implemented in a service gateway include
Earlier in chapter 4 when I introduced Eureka, I talked about how centralized load balancers can be single point of failure and a bottleneck for your services. A service gateway, if not implemented correctly, can carry the same risk. Keep the following in mind as you build your service gateway implementation.
Load balancers are still useful when out in front of individual groups of services. In this case, a load balancer sitting in front of multiple service gateway instances is an appropriate design and ensures your service gateway implementation can scale. Having a load balancer sit in front of all your service instances isn’t a good idea because it becomes a bottleneck.
Keep any code you write for your service gateway stateless. Don’t store any information in memory for the service gateway. If you aren’t careful, you can limit the scalability of the gateway and have to ensure that the data gets replicated across all service gateway instances.
Keep the code you write for your service gateway light. The service gateway is the “chokepoint” for your service invocation. Complex code with multiple database calls can be the source of difficult-to-track-down performance problems in the service gateway.
Let’s now look at how to implement a service gateway using Spring Cloud and Netflix Zuul.
Spring Cloud integrates with the Netflix open source project Zuul. Zuul is a services gateway that’s extremely easy to set up and use via Spring Cloud annotations. Zuul offers a number of capabilities, including
To get started with Zuul, you’re going to do three things:
If you’ve been following the chapters sequentially in this book, the work you’re about to do should be familiar. To build a Zuul server, you need to set up a new Spring Boot service and define the corresponding Maven dependencies. You can find the project source code for this chapter in the GitHub repository for this book (https://github.com/carnellj/spmia-chapter6). Fortunately, little is needed to set up Zuul in Maven. You only need to define one dependency in your zuulsvr/pom.xml file:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
This dependency tells the Spring Cloud framework that this service will be running Zuul and initialize Zuul appropriately.
After you’ve defined the maven dependencies, you need to annotate the bootstrap class for the Zuul services. The bootstrap class for the Zuul service implementation can be found in the zuulsvr/src/main/java/com/thoughtmechanix/zuulsvr/Application.java class.

That’s it. There’s only one annotation that needs to be in place: @EnableZuulProxy.
If you look through the documentation or have auto-complete turned on, you might notice an annotation called @EnableZuulServer. Using this annotation will create a Zuul Server that doesn’t load any of the Zuul reverse proxy filters or use Netflix Eureka for service discovery. (We’ll get into the topic of Zuul and Eureka integration shortly.) @EnableZuulServer is used when you want to build your own routing service and not use any Zuul pre-built capabilities. An example of this would be if you wanted to use Zuul to integrate with a service discovery engine other than Eureka (for example, Consul). We’ll only use the @EnableZuulProxy annotation in this book.
The Zuul proxy server is designed by default to work on the Spring products. As such, Zuul will automatically use Eureka to look up services by their service IDs and then use Netflix Ribbon to do client-side load balancing of requests from within Zuul.
I often read chapters out of order in a book, jumping to the specific topics I’m most interested in. If you do the same and don’t know what Netflix Eureka and Ribbon are, I suggest you read chapter 4 before proceeding much further. Zuul uses those technologies heavily to carry out work, so understanding the service discovery capabilities that Eureka and Ribbon bring to the table will make understanding Zuul that much easier.
The last step in the configuration process is to modify your Zuul server’s zuulsvr/src/main/resources/application.yml file to point to your Eureka server. The following listing shows the Zuul configuration needed for Zuul to communicate with Eureka. The configuration in the listing should look familiar because it’s the same configuration we walked through in chapter 4.
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
Zuul at its heart is a reverse proxy. A reverse proxy is an intermediate server that sits between the client trying to reach a resource and the resource itself. The client has no idea it’s even communicating to a server other than a proxy. The reverse proxy takes care of capturing the client’s request and then calls the remote resource on the client’s behalf.
In the case of a microservices architecture, Zuul (your reverse proxy) takes a microservice call from a client and forwards it onto the downstream service. The service client thinks it’s only communicating with Zuul. For Zuul to communicate with the downstream clients, Zuul has to know how to map the incoming call to a downstream route. Zuul has several mechanisms to do this, including
All route mappings for Zuul are done by defining the routes in the zuulsvr/src/main/resources/application.yml file. However, Zuul can automatically route requests based on their service IDs with zero configuration. If you don’t specify any routes, Zuul will automatically use the Eureka service ID of the service being called and map it to a downstream service instance. For instance, if you wanted to call your organizationservice and used automated routing via Zuul, you would have your client call the Zuul service instance, using the following URL as the endpoint:
http://localhost:5555/organizationservice/v1/organizations/e254f8c-c442-4ebe-a82a-e2fc1d1ff78a
Your Zuul server is accessed via http://localhost:5555. The service you’re trying (organizationservice) to invoke is represented by the first part of the endpoint path in the service.
Figure 6.3 illustrates this mapping in action.

The beauty of using Zuul with Eureka is that not only do you now have a single endpoint that you can make calls through, but with Eureka, you can also add and remove instances of a service without ever having to modify Zuul. For instance, you can add a new service to Eureka, and Zuul will automatically route to it because it’s communicating with Eureka about where the actual physical services endpoints are located.
If you want to see the routes being managed by the Zuul server, you can access the routes via the /routes endpoint on the Zuul server. This will return a listing of all the mappings on your service. Figure 6.4 shows the output from hitting http://localhost:5555/routes.

In figure 6.4 the mappings for the services registered with Zuul are shown on the left-hand side of the JSON body returned from the /route calls. The actual Eureka service IDs the routes map to are shown on the right.
Zuul allows you to be more fine-grained by allowing you to explicitly define route mappings rather than relying solely on the automated routes created with the service’s Eureka service ID. Suppose you wanted to simplify the route by shortening the organization name rather than having your organization service accessed in Zuul via the default route of /organizationservice/v1/organizations/{organization-id}. You can do this by manually defining the route mapping in zuulsvr/src/main/resources/application.yml:
zuul: routes: organizationservice: /organization/**
By adding this configuration, you can now access the organization service by hitting the /organization/v1/organizations/{organization-id} route. If you check the Zuul server’s endpoint again, you should see the results shown in figure 6.5.

If you look carefully at figure 6.5 you’ll notice that two entries are present for the organization service. The first service entry is the mapping you defined in the application.yml file: "organization/**": "organizationservice". The second service entry is the automatic mapping created by Zuul based on the organization service’s Eureka ID: "/organizationservice/**": "organizationservice".
When you use automated route mapping where Zuul exposes the service based solely on the Eureka service ID, if no instances of the service are running, Zuul will not expose the route for the service. However, if you manually map a route to a service discovery ID and there are no instances registered with Eureka, Zuul will still show the route. If you try to call the route for the non-existent service, Zuul will return a 500 error.
If you want to exclude the automated mapping of the Eureka service ID route and only have available the organization service route that you’ve defined, you can add an additional Zuul parameter to your application.yml file, called ignored-services. The following code snippet shows how the ignored-services attribute can be used to exclude the Eureka service ID organizationservice from the automated mappings done by Zuul:
zuul: ignored-services: 'organizationservice' routes: organizationservice: /organization/**
The ignored-services attribute allows you to define a comma-separated list of Eureka service-IDs that you want to exclude from registration. Now, when your call the /routes endpoint on Zuul, you should only see the organization service mapping you’ve defined. Figure 6.6 shows the outcome of this mapping.

If you want to exclude all Eureka-based routes, you can set the ignored--services attribute to “*”.
A common pattern with a service gateway is to differentiate API routes vs. content routes by prefixing all your service calls with a type of label such as /api. Zuul supports this by using the prefix attribute in the Zuul configuration. Figure 6.7 lays out conceptually what this mapping prefix will look like.

In the following listing, we’ll see how to set up specific routes to your individual organization and Licensing services, exclude all of the eureka-generated services, and prefix your services with a /api prefix.

Once this configuration is done and the Zuul service has been reloaded, you should see the following two entries when hitting the /route endpoint: /api/organization and /api/licensing. Figure 6.8 shows these entries.

Let’s now look at how you can use Zuul to map to static URLs. Static URLs are URLs that point to services that aren’t registered with a Eureka service discovery engine.
Zuul can be used to route services that aren’t managed by Eureka. In these cases, Zuul can be set up to directly route to a statically defined URL. For example, let’s imagine that your license service is written in Python and you want to still proxy it through Zuul. You’d use the Zuul configuration in the following listing to achieve this.


Once this configuration change has been made, you can hit the /routes endpoint and see the static route added to Zuul. Figure 6.10 shows the results from the /routes listing.

At this point, the licensestatic endpoint won’t use Eureka and will instead directly route the request to the http://licenseservice-static:8081 endpoint. The problem is that by bypassing Eureka, you only have a single route to point requests at. Fortunately, you can manually configure Zuul to disable Ribbon integration with Eureka and then list the individual service instances that ribbon will load balance against. The following listing shows this.

Once this configuration is in place, a call to the /routes endpoint now shows that the /api/licensestatic route has been mapped to a service ID called licensestatic. Figure 6.10 shows this.
The problem with statically mapping routes and disabling Eureka support in Ribbon is that you’ve disabled Ribbon support for all your services running through your Zuul service gateway. This means that more load will be placed on your Eureka servers because Zuul can’t use Ribbon to cache the look-up of services. Remember, Ribbon doesn’t call Eureka every time it makes a call. Instead, it caches the location of the service instances locally and then checks with Eureka periodically for changes. With Ribbon out of the picture, Zuul will call Eureka every time it needs to resolve the location of a service.
Earlier in the chapter, I talked about how you might end up with multiple service gateways where different routing rules and policies would be enforced based on the type of services being called. For non-JVM applications, you could set up a separate Zuul server to handle these routes. However, I’ve found that with non-JVM-based languages, you’re better off setting up a Spring Cloud “Sidecar” instance. The Spring Cloud sidecar allows you to register non-JVM services with a Eureka instance and then proxy them through Zuul. I don’t cover Spring Sidecar in this book because you’re not writing any non-JVM services, but it’s extremely easy to set up a sidecar instance. Directions on how to do so can be found at the Spring Cloud website (http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html#spring-cloud-ribbon-without-eureka).
The next thing we’re going to look at in terms of configuring routes in Zuul is how to dynamically reload routes. The ability to dynamically reload routes is useful because it allows you to change the mapping of routes without having to recycle the Zuul server(s). Existing routes can be modified quickly and new routes added within have to go through the act of recycling each Zuul server in your environment. In chapter 3, we covered how to use Spring Cloud Configuration service to externalize a microservices configuration data. You can use Spring Cloud configuration to externalize Zuul routes. In the EagleEye examples you can set up a new application folder in your config-repo (http://github.com/carnellj/config-repo) called zuulservice. Like your organization and licensing services, you’ll create three files—zuulservice.yml, zuulservice-dev.yml, and zuulservice-prod.yml—that will hold your route configuration.
To be consistent with the examples in the chapter 3 configuration, I’ve changed the route formats to move from a hierarchical format to the “.” format. The initial route configuration will have a single entry in it:
zuul.prefix=/api
If you hit the /routes endpoint, you should see all your Eureka-based services currently shown in Zuul with the prefix of /api. Now, if you wanted to add new route mappings on the fly, all you have to do is make the changes to the config file and then commit them back to the Git repository where Spring Cloud Config is pulling its configuration data from. For instance, if you wanted to disable all Eureka-based service registration and only expose two routes (one for the organization and one for the licensing service), you could modify the zuulservice-*.yml files to look like this:
zuul.ignored-services: '*' zuul.prefix: /api zuul.routes.organizationservice: /organization/** zuul.routes.organizationservice: /licensing/**
Then you can commit the changes to GitHub. Zuul exposes a POST-based endpoint route /refresh that will cause it to reload its route configuration. Once this /refresh is hit, if you then hit the /routes endpoint, you’ll see that the two new routes are exposed and all the Eureka-based routes are gone.
Zuul uses Netflix’s Hystrix and Ribbon libraries to help prevent long-running service calls from impacting the performance of the services gateway. By default, Zuul will terminate and return an HTTP 500 error for any call that takes longer than one second to process a request. (This is the Hystrix default.) Fortunately, you can configure this behavior by setting the Hystrix timeout properties in your Zuul server’s configuration.
To set the Hystrix timeout for all of the services running through Zuul, you can use the hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds property. For instance, if you wanted to set the default Hystrix time out to be 2.5 seconds, you could use the following configuration in your Zuul’s Spring Cloud config file:
zuul.prefix: /api zuul.routes.organizationservice: /organization/** zuul.routes.licensingservice: /licensing/** zuul.debug.request: true hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 2500
If you need to set the Hystrix timeout for specific service, you can replace the default part of the property with the Eureka service ID name of the service whose timeout you want to override. For instance, if you wanted to change only the licensingservice’s timeout to three seconds and leave the rest of the services to use the default Hystrix timeout, you could use something like this in your configuration:
hystrix.command.licensingservice.execution.isolation.thread.timeoutInMilliseconds: 3000
Finally, you need to be aware of one other timeout property. While you’ve overridden the Hystrix timeout, the Netflix Ribbon also times out any calls that take longer than five seconds. While I highly recommend you revisit the design of any call that takes longer than five seconds, you can override the Ribbon timeout by setting the following property: servicename.ribbon.ReadTimeout. For example, if you wanted to override the licensingservice to have a seven-second timeout, you’d use the following configuration:
hystrix.command.licensingservice.execution.isolation.thread.timeoutInMilliseconds: 7000 licensingservice.ribbon.ReadTimeout: 7000
For configurations longer than five seconds you have to set both the Hystrix and the Ribbon timeouts.
While being able to proxy all requests through the Zuul gateway does allow you to simplify your service invocations, the real power of Zuul comes into play when you want to write custom logic that will be applied against all the service calls flowing through the gateway. Most often this custom logic is used to enforce a consistent set of application policies like security, logging, and tracking against all the services.
These application policies are considered cross-cutting concerns because you want them to be applied to all the services in your application without having to modify each service to implement them. In this fashion, Zuul filters can be used in a similar way as a J2EE servlet filter or a Spring Aspect that can intercept a wide body of behaviors and decorate or change the behavior of the call without the original coder being aware of the change. While a servlet filter or Spring Aspect is localized to a specific service, using Zuul and Zuul filters allows you implement cross-cutting concerns across all the services being routed through Zuul.
Zuul allows you to build custom logic using a filter within the Zuul gateway. A filter allows you to implement a chain of business logic that each service request passes through as it’s being implemented.
Zuul supports three types of filters:
Figure 6.11 shows how the pre-, post, and route filters fit together in terms of processing a service client’s request.

If you follow the flow laid out in figure 6.11, you’ll see everything start with a service client making a call to a service exposed through the service gateway. From there the following activities take place:
The best way to understand how to implement Zuul filters is to see them in use. To this end, in the next several sections you’ll build a pre-, route, and post filter and then run service client requests through them.
Figure 6.12 shows how these filters will fit together in processing requests to your EagleEye services.

Following the flow of figure 6.12, you’ll see the following filters being used:
Building filters in Zuul is an extremely simple activity. To begin, you’ll build a Zuul pre-filter, called the TrackingFilter, that will inspect all incoming requests to the gateway and determine whether there’s an HTTP header called tmx-correlation-id present in the request. The tmx-correlation-id header will contain a unique GUID (Globally Universal Id) that can be used to track a user’s request across multiple microservices.
We discussed the concept of a correlation ID in chapter 5. Here we’re going to walk through in more detail how to use Zuul to generate a correlation ID. If you skipped around in the book, I highly recommend you look at chapter 5 and read the section on Hystrix and Thread context. Your implementation of correlation IDs will be implemented using ThreadLocal variables and there’s extra work to do to have ThreadLocal variables work with Hystrix.
If the tmx-correlation-id isn’t present on the HTTP header, your Zuul TrackingFilter will generate and set the correlation ID. If there’s already a correlation ID present, Zuul won’t do anything with the correlation ID. The presence of a correlation ID means that this particular service call is part of a chain of service calls carrying out the user’s request. In this case, your TrackingFilter class will do nothing.
Let’s go ahead and look at the implementation of the TrackingFilter in the following listing. This code can also be found in the book samples in zuulsvr/src/main/java/com/thoughtmechanix/zuulsvr/filters/TrackingFilter.java.


To implement a filter in Zuul, you have to extend the ZuulFilter class and then override four methods: filterType(), filterOrder(), shouldFilter(), and run(). The first three methods in this list describe to Zuul what type of filter you’re building, what order it should be run in compared to the other filters of its type, and whether it should be active. The last method, run(), contains the business logic the filter is going to implement.
You’ve implemented a class called FilterUtils. This class is used to encapsulate common functionality used by all your filters. The FilterUtils class is located in the zuulsvr/src/main/java/com/thoughtmechanix/zuulsvr/FilterUtils.java. We’re not going to walk through the entire FilterUtils class, but the key methods we’ll discuss here are the getCorrelationId() and setCorrelationId() functions. The following listing shows the code for the FilterUtils getCorrelationId() method.
public String getCorrelationId(){
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.getRequest()
.getHeader(CORRELATION_ID) !=null) {
return ctx.getRequest()
.getHeader(CORRELATION_ID);
}
else{
return ctx.getZuulRequestHeaders()
.get(CORRELATION_ID);
}
}
The key thing to notice in listing 6.7 is that you first check to see if the tmx-correlation-ID is already set on the HTTP Headers for the incoming request. You do this using the ctx.getRequest().getHeader(CORRELATION_ID) call.
In a normal Spring MVC or Spring Boot service, the RequestContext would be of type org.springframework.web.servletsupport.Request- Context. However, Zuul gives a specialized RequestContext that has several additional methods for accessing Zuul-specific values. This request context is part of the com.netflix.zuul.context package.
If it isn’t there, you then check the ZuulRequestHeaders. Zuul doesn’t allow you to directly add or modify the HTTP request headers on an incoming request. If we add the tmx-correlation-id and then try to access it again later in the filter, it won’t be available as part of the ctx.getRequestHeader() call. To work around this, you use the FilterUtils getCorrelationId() method. You may remember that earlier in the run() method on your TrackingFilter class, you did exactly this with the following code snippet:
else{
filterUtils.setCorrelationId(generateCorrelationId());
logger.debug("tmx-correlation-id generated
in tracking filter: {}.",
filterUtils.getCorrelationId());
}
The setting of the tmx-correlation-id occurs with the FilterUtils set-CorrelationId() method:
public void setCorrelationId(String correlationId){
RequestContext ctx =
RequestContext.getCurrentContext();
ctx.addZuulRequestHeader(CORRELATION_ID, correlationId);
}
In the FilterUtils setCorrelationId() method, when you want to add a value to the HTTP request headers, you use the RequestContext’s addZuulRequestHeader() method. This method will maintain a separate map of HTTP headers that were added while a request was flowing through the filters with your Zuul server. The data contained within the ZuulRequestHeader map will be merged when the target service is invoked by your Zuul server.
Now that you’ve guaranteed that a correlation ID has been added to every microservice call flowing through Zuul, how do you ensure that
To implement this, you’re going to build a set of three classes into each of your microservices. These classes will work together to read the correlation ID (along with other information you’ll add later) off the incoming HTTP request, map it to a class that’s easily accessible and useable by the business logic in the application, and then ensure that the correlation ID is propagated to any downstream service calls.
Figure 6.13 demonstrates how these different pieces are going to be built out using your licensing service.

Let’s walk through what’s happening in figure 6.13:
The subject of whether you should use common libraries across your microservices is a gray area in microservice design. Microservice purists will tell you that you shouldn’t use a custom framework across your services because it introduces artificial dependencies in your services. Changes in business logic or a bug can introduce wide scale refactoring of all your services. On the other side, other microservice practitioners will say that a purist approach is impractical because certain situations exist (like the previous UserContextFilter example) where it makes sense to build a common library and share it across services.
I think there’s a middle ground here. Common libraries are fine when dealing with infrastructure-style tasks. If you start sharing business-oriented classes, you’re asking for trouble because you’re breaking down the boundaries between the services.
I seem to be breaking my own advice with the code examples in this chapter, because if you look at all the services in the chapter, they all have their own copies of the UserContextFilter, UserContext, and UserContextInterceptor classes. The reason I took a share-nothing approach here is that I don’t want to complicate the code examples in this book by having to create a shared library that would have to be published to a third-party Maven repository. Hence, all the classes in the utils package of the service are shared across all the services.
The first class you’re going to build is the UserContextFilter class. This class is an HTTP servlet filter that will intercept all incoming HTTP requests coming into the service and map the correlation ID (and a few other values) from the HTTP request to the UserContext class. The following listing shows the code for the UserContext class. The source for this class can be found in licensing-service/src/main/java/com/thoughtmechanix/licenses/utils/UserContextFilter.java.


Ultimately, the UserContextFilter is used to map the HTTP header values you’re interested in into a Java class, UserContext.
The UserContext class is used to hold the HTTP header values for an individual service client request being processed by your microservice. It consists of a getter/setter method that retrieves and stores values from java.lang.ThreadLocal. The following listing shows the code from the UserContext class. The source for this class can be found in licensing-service/src/main/java/com/thoughtmechanix/-licenses/utils/UserContext.java.
@Component
public class UserContext {
public static final String CORRELATION_ID = "tmx-correlation-id";
public static final String AUTH_TOKEN = "tmx-auth-token";
public static final String USER_ID = "tmx-user-id";
public static final String ORG_ID = "tmx-org-id";
private String correlationId= new String();
private String authToken= new String();
private String userId = new String();
private String orgId = new String();
public String getCorrelationId() { return correlationId;}
public void setCorrelationId(String correlationId) {
this.correlationId = correlationId;}
public String getAuthToken() { return authToken;}
public void setAuthToken(String authToken) {
this.authToken = authToken;}
public String getUserId() { return userId;}
public void setUserId(String userId) { this.userId = userId;}
public String getOrgId() { return orgId;}
public void setOrgId(String orgId) {this.orgId = orgId;
}
}
Now the UserContext class is nothing more than a POJO holding the values scraped from the incoming HTTP request. You use a class called zuulsvr/src/main/java/com/thoughtmechanix/zuulsvr/filters/UserContextHolder.java to store the UserContext in a ThreadLocal variable that is accessible in any method being invoked by the thread processing the user’s request. The code for UserContextHolder is shown in the following listing.
public class UserContextHolder {
private static final ThreadLocal<UserContext> userContext
= new ThreadLocal<UserContext>();
public static final UserContext getContext(){
UserContext context = userContext.get();
if (context == null) {
context = createEmptyContext();
userContext.set(context);
}
return userContext.get();
}
public static final void setContext(UserContext context) {
Assert.notNull(context,
"Only non-null UserContext instances are permitted");
userContext.set(context);
}
public static final UserContext createEmptyContext(){
return new UserContext();
}
}
The last piece of code that we’re going to look at is the UserContextInterceptor class. This class is used to inject the correlation ID into any outgoing HTTP-based service requests being executed from a RestTemplate instance. This is done to ensure that you can establish a linkage between service calls.
To do this you’re going to use a Spring Interceptor that’s being injected into the RestTemplate class. Let’s look at the UserContextInterceptor in the following listing.

To use the UserContextInterceptor you need to define a RestTemplate bean and then add the UserContextInterceptor to it. To do this, you’re going to add your own RestTemplate bean definition to the licensing-service/src/main/java/com/thoughtmechanix/licenses/Application.java class. The following listing shows the method that’s added to this class.

With this bean definition in place, any time you use the @Autowired annotation and inject a RestTemplate into a class, you’ll use the RestTemplate created in listing 6.11 with the UserContextInterceptor attached to it.
Now that you have correlation ID’s being passed to each service, it’s possible to trace a transaction as it flows through all the services involved in the call. To do this you need to ensure that each service logs to a central log aggregation point that captures log entries from all of your services into a single point. Each log entry captured in the log aggregation service will have a correlation ID associated to each entry. Implementing a log aggregation solution is outside the scope of this chapter, but in chapter 9, we’ll see how to use Spring Cloud Sleuth. Spring Cloud Sleuth won’t use the TrackingFilter that you built here, but it will use the same concepts of tracking the correlation ID and ensuring that it’s injected in every call.
Remember, Zuul executes the actual HTTP call on behalf of the service client. Zuul has the opportunity to inspect the response back from the target service call and then alter the response or decorate it with additional information. When coupled with capturing data with the pre-filter, a Zuul post filter is an ideal location to collect metrics and complete any logging associated with the user’s transaction. You’ll want to take advantage of this by injecting the correlation ID that you’ve been passing around to your microservices back to the user.
You’re going to do this by using a Zuul post filter to inject the correlation ID back into the HTTP response headers being passed back to the caller of the service. This way, you can pass the correlation ID back to the caller without ever having to touch the message body. The following listing shows the code for building a post filter. This code can be found in zuulsvr/src/main/java/com/thoughtmechanix/zuulsvr/filters/ResponseFilter.java.


Once the ResponseFilter has been implemented, you can fire up your Zuul service and call the EagleEye licensing service through it. Once the service has completed, you’ll see a tmx-correlation-id on the HTTP response header from the call. Figure 6.14 shows the tmx-correlation-id being sent back from the call.

Up until this point, all our filter examples have dealt with manipulating the service client calls before and after it has been routed to its target destination. For our last filter example, let’s look at how you can dynamically change the target route you want to send the user to.
The last Zuul filter we’ll look at is the Zuul route filter. Without a custom route filter in place, Zuul will do all its routing based on the mapping definitions you saw earlier in the chapter. However, by building a Zuul route filter, you can add intelligence to how a service client’s invocation will be routed.
In this section, you’ll learn about Zuul’s route filter by building a route filter that will allow you to do A/B testing of a new version of a service. A/B testing is where you roll out a new feature and then have a percentage of the total user population use that feature. The rest of the user population still uses the old service. In this example, you’re going to simulate rolling out a new version of the organization service where you want 50% of the users go to the old service and 50% of the users to go to the new service.
To do this you’re going to build a Zuul route filter, called SpecialRoutes-Filter, that will take the Eureka service ID of the service being called by Zuul and call out to another microservice called SpecialRoutes. The SpecialRoutes service will check an internal database to see if the service name exists. If the targeted service name exists, it will return a weight and target destination of an alternative location for the service. The SpecialRoutesFilter will then take the weight returned and, based on the weight, randomly generate a number that will be used to determine whether the user’s call will be routed to the alternative organization service or to the organization service defined in the Zuul route mappings. Figure 6.15 shows the flow of what happens when the SpecialRoutesFilter is used.

In figure 6.15, after the service client has called a service “fronted” by Zuul, the SpecialRoutesFilter takes the following actions:
We’re going to start walking through the code you used to build the SpecialRoutesFilter. Of all the filters we’ve looked at so far, implementing a Zuul route filter requires the most coding effort, because with a route filter you’re taking over a core piece of Zuul functionality, routing, and replacing it with your own functionality. We’re not going to go through the entire class in detail here, but rather work through the pertinent details.
The SpecialRoutesFilter follows the same basic pattern as the other Zuul filters. It extends the ZuulFilter class and sets the filterType() method to return the value of “route”. I’m not going to go into any more explanation of the filter-Order() and shouldFilter() methods as they’re no different from the previous filters discussed earlier in the chapter. The following listing shows the route filter skeleton.
package com.thoughtmechanix.zuulsvr.filters;
@Component
public class SpecialRoutesFilter extends ZuulFilter {
@Override
public String filterType() {
return filterUtils.ROUTE_FILTER_TYPE;
}
@Override
public int filterOrder() {}
@Override
public boolean shouldFilter() {}
@Override
public Object run() {}
}
The real work for the SpecialRoutesFilter begins in the run() method of the code. The following listing shows the code for this method.

The general flow of code in listing 6.15 is that when a route request hits the run() method in the SpecialRoutesFilter, it will execute a REST call to the SpecialRoutes service. This service will execute a lookup and determine if a routing record exists for the Eureka service ID of the target service being called. The call out to SpecialRoutes service is done in the getAbRoutingInfo() method. The get-AbRoutingInfo() method is shown in the following listing.

Once you’ve determined that there’s a routing record present for the target service, you need to determine whether you should route the target service request to the alternative service location or to the default service location statically managed by the Zuul route maps. To make this determination, you call the useSpecialRoute() method. The following listing shows this method.

This method does two things. First, the method checks the active field on the AbTestingRoute record returned from the SpecialRoutes service. If the record is set to "N," useSpecialRoute() method shouldn’t do anything because you don’t want to do any routing at this moment. Second, the method generates a random number between 1 and 10. The method will then check to see if the weight of the return route is less than the randomly generated number. If the condition is true, the useSpecialRoute method returns true indicating you do want to use the route.
Once you’ve determined that you do want to route the service request coming into the SpecialRoutesFilter, you’re going to forward the request onto the target service.
The actual forwarding of the route to the downstream service is where the majority of the work occurs in the SpecialRoutesFilter. While Zuul does provide helper functions to make this task easier, the majority of the work still lies with the developer. The forwardToSpecialRoute() method does the forwarding work for you. The code in this method borrows heavily from the source code for the Spring Cloud SimpleHost-RoutingFilter class. While we’re not going to go through all of the helper functions called in the forwardToSpecialRoute() method, we’ll walk through the code in this method, as shown in the following listing.


The key takeaway from the code in listing 6.18 is that you’re copying all of the values from the incoming HTTP request (the header parameters, HTTP verb, and the body) into a new request that will be invoked on the target service. The forwardToSpecial-Route() method then takes the response back from the target service and sets it on the HTTP request context used by Zuul. This is done via the setResponse() helper method (not shown). Zuul uses the HTTP request context to return the response back from the calling service client.
Now that you’ve implemented the SpecialRoutesFilter you can see it an action by calling the licensing service. As you may remember from earlier chapters, the licensing service calls the organization service to retrieve the contact data for the organization.
In the code example, the specialroutesservice has a database record for the organization service that will route the requests for calls to the organization service 50% of the time to the existing organization service (the one mapped in Zuul) and 50% of the time to an alternative organization service. The alternative organization service route returned from the SpecialRoutes service will be http://orgservice-new and will not be accessible directly from Zuul. To differentiate between the two services, I’ve modified the organization service(s) to pre-pend the text “OLD::” and “NEW::” to contact names returned by the organization service.
If you now hit the licensing service endpoint through Zuul
http://localhost:5555/api/licensing/v1/organizations/e254f8c-c442-4ebe-a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a
you should see the contactName returned from the licensing service call flip between the OLD:: and NEW:: values. Figure 6.16 shows this.

A Zuul routes filter does take more effort to implement then a pre- or post filter, but it’s also one of the most powerful parts of Zuul because you’re able to easily add intelligence to the way your services are routed.