Through the previous sharing, we have learned about several core facilities of microservice architecture, through these components, we can build a simple microservice architecture system. For example, build a highly available service registration center through Spring Cloud Eureka and realize service registration and discovery;
Load balancing with Spring Cloud Ribbon or Feign; service fault-tolerant protection with Spring Cloud Hystrix to avoid spreading failures. After the microservice is built, we will definitely provide some unified RESTFul API service interface to the external system for call.
But when the external system calls our RESTful API, how do you determine which service it needs to provide the specific functions it requires? This involves the maintenance of routing rules and service instance lists.
This introduces our protagonist today - Spring Cloud Zuul, which is an API gateway component based on Netflix Zuul implementation. It can solve two major problems:
OK, let’s take a look at how to implement this gateway service.
1. Build a gateway and configure routing
Here we still need to use the previous hello-service and feign-consumer services. We used to regard feign-consumer as a service consumer, but don't forget that in the eureka system, each service is both a service provider and a service consumer, so feign-consumer is also a service provider, and interfaces such as http://localhost:9001/feign-consumer are the services it provides.
Next, we build a gateway service with the code structure as follows:
Code implementation steps:
Create a new maven project api-gateway
Modify POM file
<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.sam</groupId> <artifactId>api-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <properties> <javaVersion>1.8</javaVersion> </properties> <!-- Use dependencyManagement for version management --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</version> <type>pom</type> <scope>import</scope> </dependency> </dependency> </dependencyManagement> <dependencies> <!-- Introducing zuul dependency, which relies on spring-boot-starter-actuator/spring-boot-starter-hystrix/spring-boot-starter-ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> </dependencies></project>
Create a new startup class
/** * @EnableZuulProxy Enable Zuul's API gateway service function* */@EnableZuulProxy@SpringCloudApplicationpublic class GateWayApp { public static void main(String[] args) { SpringApplication.run(GateWayApp.class, args); }}Create new application.properties
server.port=5555spring.application.name=api-gateway#Add to the configuration of routing rules#Configure through zuul.routes.<route>.path and zuul.routes.<route>.url. <route> is the name of the route and can be specified arbitrarily, but the route names of a set of paths and urls should be the same#As shown in the following example: All satisfy /api-a/** Access to rules will be routed to the address of //localhost:9001#, that is, when we access http://localhost:5555/api-a/hello, the API gateway service will route the request to the microservice interface provided by http://localhost:9001/hello zuul.routes.api-a.path=/api-a/**zuul.routes.api-a.url=http://localhost:9001zuul.routes.api-b.path=/api-b/**zuul.routes.api-b.url=http://localhost:9090
Test, start eureka, hello-service, feign-consumer and the newly added api-gateway service, and then visit http://localhost:5555/api-a/feign-consumer
Successfully accessed the service interface of feign-consumer --feign-consonsumer.
The above steps implement the configuration of traditional routing. This configuration has a major disadvantage, which is that it requires manual configuration of routing rules in the application.properties file. When there are a lot of services, the maintenance workload will be very large. In order to reduce maintenance costs, there is another route - service-oriented route.
2. Service-oriented routing
Spring Cloud Zuul and Eureka integrate, we can make the route path not map specific urls, but specific services, and the service urls are automatically maintained by Eureka service discovery mechanism. This type of route is service-oriented route. The specific code configuration is as follows:
Modify POM files and introduce Eureka dependencies
<!-- Introducing eureka dependencies--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
Modify the application.properties configuration file
server.port=5555spring.application.name=api-gatewayzuul.routes.api-a.path=/api-a/**# Here we use serviceId instead of url, and use service name instead of ip+port number zuul.routes.api-a.serviceId=hello-serviceeureka.client.service-url.defaultZone=http://localhost:1111/eureka
Note: zuul.routes.api-a.url=hello-service can also implement functions, but it cannot perform normal load balancing and fault-tolerant protection.
Test, visit http://localhost:5555/api-a/hello
The access was successful.
3. Default rules for service routing
In service-oriented routes, since the <route> name is arbitrarily, is this possible:
zuul.routes.hello-service.path=/hello-service/**zuul.routes.hello-service.serviceId=hello-service
<route> name is the service name. In fact, in actual applications, we often name it this way. If there are such rules, Zuul can help us implement such functions by default, further saving the trouble of configuration.
Let's do an experiment and change the configuration file to:
server.port=5555spring.application.name=api-gatewayeureka.client.service-url.defaultZone=http://localhost:1111/eureka
Then page access verification
The access was successful.
However, by default, the services on Eureka will be routed by Zuul creating default mapping relationships, so that services that we do not want to be open to the outside world are also accessed externally. At this time, we can configure rules that do not require automatic routing creation by zuul.ignored-services. When zuul.ignored-services=*, all services will not automatically create routing rules. At this time, the relevant routing configuration needs to be performed through the previous configuration.
=================== Gorgeous dividing line========================
So much has been said before, all revolve around one problem: routing rules and service instance maintenance issues. So how to solve the second problem (checking redundancy problem)?
4. Request filtering
In order to verify client requests in the API gateway, we can use filters to intercept and filter requests. The implementation method is relatively simple. You only need to inherit the ZuulFilter abstract class and implement its four methods.
Modify api-gateway:
Added filter class
/** * Inheriting ZuulFilter and implementing its 4 interfaces* * for request filtering* */public class AccessFilter extends ZuulFilter { Logger logger = LoggerFactory.getLogger(AccessFilter.class); /* * shouldFilter determines whether the filter needs to be executed* * Return true here, indicating that the filter will take effect on all requests. * In actual use, we can use this function to specify the effective range of the filter*/ @Override public boolean shouldFilter() { return true; } /* * Specific logic of the filter* * Here we ask zuul to request via ctx.setSendZuulResponse(false) and do not route it* Then we set the returned error code through ctx.setResponseStatusCode(401)* */ @Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); Object accessToken = request.getParameter("accessToken"); logger.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); if(accessToken == null) { context.setSendZuulResponse(false); context.setResponseStatusCode(401); } return null; } /* filterType Returns the filter type* It determines which lifecycle the filter is executed in. This is defined as pre, which means that the request will be executed before it is routed. * * pre: filter before request execution * route: Process the request and route * post: filter executed after request processing is completed * error: filter executed when an error occurs */ @Override public String filterType() { return "pre"; } /* * filterOrder Returns the order of execution of the filter* * When the request has multiple filters in one stage, it is necessary to execute it once based on the return value of the method * */ @Override public int filterOrder() { return 0; }}Modify the startup class
/** * @EnableZuulProxy Enable Zuul's API gateway service function* */@EnableZuulProxy@SpringCloudApplicationpublic class GateWayApp { //The bean is added to implement @Bean public AccessFilter accessFilter() { return new AccessFilter(); } public static void main(String[] args) { SpringApplication.run(GateWayApp.class, args); }}test
) Visit http://localhost:5555/hello-service/hello, the access failed
) Visit http://localhost:5555/hello-service/hello?accessToken=token, access normally
Modified code structure:
5. Expand and extend
In fact, when the routing function is actually running, its routing mapping and request forwarding are all done by several different filters.
The routing mapping is mainly completed through pre-type filters, which matches the request path with the configured routing rules and finds the target address that needs to be forwarded.
The request forwarding part is completed by a route filter, which forwards the route address obtained by the pre-type filter.
Therefore, filters can be said to be the most core component of Zuul's API gateway function. Each HTTP request entering Zuul will be responded to through a series of filter processing chains and returned to the client.
Summarize
The above is the problem of using Zuul to implement API gateway service in spring cloud. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support to Wulin.com website!