本指南将引导您使用Netflix Zuul边缘服务库将请求路由和过滤到微服务应用程序。
你会建立什么
您将编写一个简单的微服务应用程序,然后构建一个使用Netflix Zuul将请求转发到该服务应用程序的反向代理应用程序。您还将看到如何使用Zuul过滤通过代理服务发出的请求。
你需要什么
-
约15分钟
-
最喜欢的文本编辑器或IDE
-
JDK 1.8或更高版本
-
您还可以将代码直接导入到IDE中:
如何完成本指南
像大多数Spring 入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都可以使用工作代码。
要从头开始 ,请继续使用Gradle构建 。
要跳过基础知识 ,请执行以下操作:
-
下载并解压缩本指南的源存储库,或使用Git对其进行克隆:
git clone https://github.com/spring-guides/gs-routing-and-filtering.git
-
光盘进入
gs-routing-and-filtering/initial
-
继续设置微服务 。
完成后 ,您可以根据中的代码检查结果gs-routing-and-filtering/complete
。
用Gradle构建
用Gradle构建
首先,您设置一个基本的构建脚本。在使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含使用Gradle和Maven所需的代码。如果您都不熟悉,请参阅使用Gradle 构建Java项目或使用Maven构建Java项目 。
创建目录结构
在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello
在* nix系统上:
└── src └── main └── java └── hello
创建一个Gradle构建文件
以下是最初的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 = 'gateway'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.cloud:spring-cloud-starter-zuul')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.SR5"
}
}
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插件提供了许多方便的功能:
-
它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。
-
它搜索
public static void main()
标记为可运行类的方法。 -
它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。
用Maven构建
用Maven构建
创建目录结构
在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello
在* nix系统上:
└── 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 https://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 https://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插件提供了许多方便的功能:
-
它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。
-
它搜索
public static void main()
标记为可运行类的方法。 -
它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。
使用您的IDE进行构建
使用您的IDE进行构建
-
阅读如何将本指南直接导入Spring Tool Suite中 。
-
在IntelliJ IDEA中阅读如何使用本指南。
设置微服务
Book服务将非常简单。编辑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
class现在是一个REST控制器。 @RestController
将该类标记为控制器类,并确保从@RequestMapping
此类中的方法将自动进行适当的转换,并直接写入HTTP响应。
说起@RequestMapping
方法,我们添加了两个: available()
和checkedOut()
。他们处理对路径的请求/available
和/checked-out
,每个只需返回String
一本书的名称。
设置应用程序名称( book
)在src/main/resources/application.properties
。
book/src/main/resources/application.properties
spring.application.name=book
server.port=8090
我们也在设定server.port
这样,当我们在本地启动和运行这两种服务时,它就不会与边缘服务冲突。
创建边缘服务
Spring Cloud Netflix包括一个嵌入式Zuul代理,我们可以通过启用@EnableZuulProxy
注解。这会将网关应用程序变成反向代理,该代理将相关的呼叫转发到其他服务,例如我们的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它应该监视的路由以及将请求转发到这些路由的服务。我们使用下面的属性指定路线zuul.routes
。我们的每个微服务都可以在zuul.routes.NAME
,在哪里NAME
是应用程序名称(存储在spring.application.name
属性)。
添加application.properties
文件到新目录, src/main/resources
,在网关应用程序中。它看起来应该像这样:
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会将请求代理到/books
到这个URL。
请注意文件中倒数第二个属性:Spring Cloud Netflix Zuul使用Netflix的Ribbon执行客户端负载平衡,默认情况下,Ribbon将使用Netflix Eureka进行服务发现。对于这个简单的示例,我们跳过了服务发现,因此我们设置了ribbon.eureka.enabled
至false
。由于Ribbon现在无法使用Eureka查找服务,因此我们必须指定一个url
图书服务。
添加过滤器
现在,让我们看看如何通过代理服务过滤请求。Zuul具有四种标准过滤器类型:
-
在路由请求之前执行预过滤器,
-
路由过滤器可以处理请求的实际路由,
-
路由请求后,将执行后置过滤器,并且
-
如果在处理请求的过程中发生错误,则执行错误过滤器。
我们将编写一个前置过滤器。Spring Cloud Netflix可以选择任何过滤器@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;
}
}
过滤器类实现四种方法:
-
filterType()
返回一个String
代表过滤器类型-在这种情况下,pre
,或者可能是route
用于路由过滤器。 -
filterOrder()
给出相对于其他过滤器执行此过滤器的顺序。 -
shouldFilter()
包含确定何时执行此过滤器的逻辑(该特定过滤器将始终执行)。 -
run()
包含过滤器的功能。
Zuul过滤器将请求和状态信息存储在(并通过以下方式共享) RequestContext
。我们正在使用它来达到HttpServletRequest
,然后在发送请求之前记录请求的HTTP方法和URL。
的GatewayApplication
该类带有注释@SpringBootApplication
,它(除其他外)等效于@Configuration
注释,指示Spring在给定的类中查找@Bean
定义。为我们添加一个SimpleFilter
这里:
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应用程序的一个端点。如果您使用了本指南中显示的配置,则可以直接在以下位置访问Book服务localhost:8090
并通过以下网关服务localhost:8080/books
。
访问以下图书服务端点之一, 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开发了一个边缘服务应用程序,该应用程序可以代理和过滤对微服务的请求。
也可以看看
以下指南也可能会有所帮助:
是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则 。
所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创作共用许可证发布 。 |