原文:Routing and Filtering译者:hh23485
校对:oshare
本指南将引导您完成使用Netflix Zuul边缘服务库来路由和过滤微服务应用程序请求。
你将会写一个简单的微服务应用,接着使用 Netflix Zuul 构建一个反向代理应用将请求转发到应用服务。你也会了解如何使用 Zuul 过滤代理服务中的请求。
你也可以将代码直接导入你的IDE:
像大多数 Spring 入门指南一样,你可以从头开始,完成每一步,也可以跳过已经熟悉的基本步骤。 无论哪种方式,你都会得到起作用的代码。
从零开始,请移步Build with Gradle.
跳过基础步骤,按照下面步骤进行:
git clone https://github.com/spring-guides/gs-routing-and-filtering.git
gs-routing-and-filtering/initial
当你完成后,你可以和此处的代码进行对比gs-routing-and-filtering/complete
.
首先你得设置基础的构建脚本. 你可以使用任意你喜欢的构建系统去构建Spring应用, 你需要使用的代码包含在这儿:Gradle and Maven . 如果你对两者都不熟悉,可以先参考Building Java Projects with Gradle 或者 Building Java Projects with Maven.
在你选择的项目目录中,创建以下子目录结构;例如, 在Linux/Unix系统中使用如下命令: mkdir -p src/main/java/hello
└── src
└── main
└── java
└── hello
如下是一个 Gradle初始化文件.
book/build.gradle
buildscript {
ext {
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
jar {
baseName = 'book'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.9'
}
gateway/build.gradle
buildscript {
ext {
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
jar {
baseName = 'book'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.9'
}
Spring Boot gradle 插件 提供了很多便捷的特性:
public static void main()
方法并标记为一个可执行的类.首先,你需要设置一个基本的构建脚本。你可以在构建Spring应用程序时使用任意你喜欢的构建系统。但是用于Maven的代码如下所示。如果你对Maven不熟悉,请参考Building Java Projects with Maven.
在你选择的项目目录中,创建以下子目录结构;例如, 在Linux/Unix系统中使用如下命令: mkdir -p src/main/java/hello
└── src
└── main
└── java
└── hello
book/pom.xml
<?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.example</groupId>
<artifactId>book</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>book</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
gateway/pom.xml
<?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.example</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot Maven 插件 提供了很多便捷的特性:
public static void main()
方法并标记为一个可执行的类.订阅服务将会特别简单,编辑BookApplication.java
使它如下所示:
book/src/main/java/hello/BookApplication.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class BookApplication {
@RequestMapping(value = "/available")
public String available() {
return "Spring in Action";
}
@RequestMapping(value = "/checked-out")
public String checkedOut() {
return "Spring Boot in Action";
}
public static void main(String[] args) {
SpringApplication.run(BookApplication.class, args);
}
}
BookApplication
类是一个Rest Controller。[@RestController](https://github.com/RestController "@RestController")
注解表示这是一个控制器类,并且也确保[@RequestMapping](https://github.com/RequestMapping "@RequestMapping")
方法的返回值会被自动转换为合适的格式并直接写入到HTTP响应中。
对于[@RequestMapping](https://github.com/RequestMapping "@RequestMapping")
方法,我们已经添加两个:available()
和checkedOut()
。他们分别处理路径为/available
和/checked-out
的请求,每一个都简单地返回String
格式的书名。
在src/main/resources/application.properties
文件中设置应用程序的名称(book
)。
spring.application.name=book
server.port=8090
我们也可以在这里设置server.port
来防止我们和边缘服务都在本地启动运行发生端口冲突。
Spring Cloud Netflix 包括了一个内嵌的Zuul代理,我们可以使用[@EnableZuulProxy](https://github.com/EnableZuulProxy "@EnableZuulProxy")
注解来启用。这能够让网关(Gateway)应用成为一个代理并转发相关的请求到其他服务中,例如我们的Book服务。
打开网关应用的GatewayApplication
类并添加该注解,如下所示:
gateway/src/main/java/hello/GatewayApplication.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
为了能够让请求从网关应用中转发出去,我们需要告诉Zuul路由信息来监测和服务并决定向什么路由进行转发。我们在properties的zuul.routes
前缀下指定路由。每一个微服务可以在zuul.routes.NAME
下定义一个入口,NAME
是应用的名称(即在spring.application.name
属性中存储的值)。
在网关应用的src/main/resources
文件夹下添加application.properties
。它应该如下所示:
gateway/src/main/resources/application.properties
zuul.routes.books.url=http://localhost:8090
ribbon.eureka.enabled=false
server.port=8080
Spring Cloud Zuul 本会根据应用的名称自动设定路径。在这例子中,因为我们设置了zuul.routes.books.url
,所以Zuul将会代理请求至/book
到该 url。
注意上述文件的第二个到最后一个属性:Spring Cloud Netflix 使用 Netflix Ribbon 来实现客户端的负载均衡。默认情况下,Ribbon 将会使用 Netflix Eureka 作为服务发现。对于一个简单的例子来说,我们跳过了服务发现应用,所以我们设置ribbon.eureka.enabled
为false
。这样,Ribbon 不会使用Eureka
来查找服务,我们必须为 Book 服务指定url
。
现在,让我们看看如何在代理服务中过滤请求。Zuul有四个标准的过滤类型:
让我们来写一个 pre 过滤器。Spring Cloud Netflix 认为所有标注了[@Bean](https://github.com/Bean "@Bean")
的com.netflix.zuul.ZuulFilter
子类都是过滤器,并且他们都能够在应用上下文中被获取到。创建一个新的目录,src/main/java/hello/filters/pre
,并且在其中创建过滤文件SimpleFilter.java
:
gateway/src/main/java/hello/filters/pre/SimpleFilter.java
package hello.filters.pre;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.ZuulFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SimpleFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
return null;
}
}
过滤器类将实现4个方法:
filterType()
返回一个String
。这代表了过滤器的类型,在该例中,pre
或者可以是route
来作为一个过滤器的路由。filterOrder()
给出过滤器执行的顺序,或者相对于其他过滤器的顺序。shouldFilter()
包含决定是否执行过滤器的逻辑,在该例中,它将会_始终_执行。run()
包含了过滤的功能。Zuul过滤器在RequestContext
中存储(或分享)请求的信息。我们可以使用它来获取HttpServletRequest
,然后我们可以在转发前记录( log )HTTP请求的方法 (HTTP method) 和URL。
GatewayApplication
类标注了[@SpringBootApplication](https://github.com/SpringBootApplication "@SpringBootApplication")
注解,这等效于(包括)[@Configuration](https://github.com/Configuration "@Configuration")
注解。该注解告诉Spring在给定的类中查找@Bean定义。为我们的SimpleFilter
在这里添加一个Bean定义。
gateway/src/main/java/hello/GatewayApplication.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import hello.filters.pre.SimpleFilter;
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public SimpleFilter simpleFilter() {
return new SimpleFilter();
}
}
确保两个应用程序都在运行。在浏览器中,通过网关应用访问Book应用。如果你使用本文前面展示的配置,你可以直接通过localhost:8090
访问Book服务,并且通过localhost:8080/books
访问基于网关的Book服务。
访问Book服务的一个终端,例如localhost:8080/books/available
,并且你可以看到在访问Book应用之前,你的请求被记录在网关应用的控制台中。
2016-01-19 16:51:14.672 INFO 58807 --- [nio-8080-exec-6] hello.filters.pre.SimpleFilter : GET request to http://localhost:8080/books/available
2016-01-19 16:51:14.672 INFO 58807 --- [nio-8080-exec-6] o.s.c.n.zuul.filters.ProxyRouteLocator : Finding route for path: /books/available
恭喜!你已经使用了Spring开发了一个可以代理和过滤微服务请求的边缘服务应用程序。
以下指南也可能有帮助:
本文由spring4all.com翻译小分队创作,采用知识共享-署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
Original url: Access
Created at: 2019-04-08 17:02:39
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论