在本教程中,学习如何启动自己的Spring Cloud API网关,以及如何使其将发送到Eureka Discovery Server Microservice注册的HTTP请求路由,以及如何在Eureka中注册多个Spring Boot微服务,以及如何配置Spring Cloud API网关以将HTTP请求路由到多个Microservice。
结合前面两节内容,包括本张内容,我们需要创建三个应用:
- Eureka Discovery Server
- Spring Boot 服务网
- Spring Cloud API 网关
启动Eureka服务
在《微服务:1.Eureka 服务发现教程》中已经创建过,为了直观期间,稍作修改:
启动类修改如下:
package com.xarhsoft.photoapp.discovery.PhotoAppDiscoveryService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class PhotoAppDiscoveryServiceApplication {
public static void main(String[] args) {
SpringApplication.run(PhotoAppDiscoveryServiceApplication.class, args);
}
}
Eureka服务的application.properties
文件修改如下:
server.port=8010
spring.application.name=PhotoAppApi-eureka-server
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
启动服务后访问http://localhost:8010
启动Spring Boot应用
在《微服务:2.向Eureka 服务器中注册服务》中已经创建过一个Spring Boot应用,修改启动类:
package com.appsdeveloperblog.photoapp.api.users;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class PhotoAppApiApplication {
public static void main(String[] args) {
SpringApplication.run(PhotoAppApiApplication.class, args);
}
}
修改对应的application.properties
内容:
eureka.client.serviceUrl.defaultZone = http://localhost:8010/eureka
server.port=0
spring.application.name=PhotoAppApi-Users
新建UsersController Class :
package com.xarhsoft.photoapp.api.users.io.controllers;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UsersController {
@GetMapping("/status/check")
public String status() {
return "Working";
}
}
启动后可以在Eureka服务中可以看到注册的微服务了。
创建Spring Cloud API网关
要创建新的Spring Cloud API 网关, 我们首先需要创建一个非常简单的Spring Boot 项目。 可以使用Spring Initializr项目页面创建Spring Boot项目。
Spring Cloud API依赖
dependenyManagement
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Gateway Starter 及 Eureka 客户端依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
repositories
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
properties
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
完整的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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.appsdeveloperblog.photoapp.gateway</groupId>
<artifactId>ApiGateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ApiGateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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>${spring-cloud.version}</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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
Spring Cloud API网关的application.properties
文件:
server.port=8080
eureka.client.serviceUrl.defaultZone = http://localhost:8010/eureka
spring.application.name=ApiGateway
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
spring.cloud.gateway.routes[0].id=users
spring.cloud.gateway.routes[0].uri=lb://PHOTOAPPAPI-USERS/users
spring.cloud.gateway.routes[0].predicates[0]=Path=/users/**
通过spring.cloud.gateway.routes
配置,将http请求中的
/users/**
映射到已经注册的微服务:
lb://PHOTOAPPAPI-USERS/user*
其中:
- PHOTOAPPAPI-USERS – 已经注册到Eureka服务的微服务名称
- lb:// – 代表负载均衡器
Spring Cloud API 网关的 bootstrap.yml 文件
可以使用bootstrap.yml
替代application.properties
文件。
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka
spring:
application:
name: ApiGateway
cloud.gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: users
uri: lb://PHOTOAPPAPI-USERS
predicates:
- Path=/users/**
配置多个路由
加入还有一个微服务命名为PHOTOAPPAPI-ALBUMS,则在yml中的配置应该修改如下:
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8010/eureka
spring:
application:
name: ApiGateway
cloud.gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: users
uri: lb://PHOTOAPPAPI-USERS
predicates:
- Path=/users/**
- id: albums
uri: lb://PHOTOAPPAPI-ALBUMS
predicates:
- Path=/albums/**
多实例中的实例ID处理
如果按照server.port=0设置端口号,则在服务注册的时候,同一个微服务的多个实例在Euroka中都会指向同一个随机出来的端口。要解决这个问题,在需要进行负载均衡的服务器的appliation.properties中按照如下方式配置:
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}
完整的application.properties
文件配置:
server.port=${PORT:0}
spring.application.name=users-ws
eureka.client.serviceUrl.defaultZone = http://localhost:8010/eureka
spring.devtools.restart.enabled = true
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}