SpringCloud + Consul服务注册中心 + gateway网关
2 创建springcloud-consul项目及三个子模块
1、首先安装Consul并启动Consul,端口号为8500
(为了安全起见, 需要设置consul 的token用于认证, 见https://www.cnblogs.com/wushengwuxi/articles/12840500.html
在application.yml中添加spring.cloud.consul.discovery.acl-token属性, https://www.cnblogs.com/duanxz/p/7049350.html)
2、创建一个maven项目springcloud-consul,修改pom.xml添加SpringBoot及SpringCloud依赖(这里展示的是最后的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.test</groupId> <artifactId>springcloud-consul</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>consul-producer</module> <module>consul-consumer</module> <module>gateway-service</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> </parent> <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> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RELEASE</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</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
创建数据提供服务模块consul-producer,修改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"> <parent> <artifactId>springcloud-consul</artifactId> <groupId>com.test</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consul-producer</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.3.1</version> </dependency> </dependencies> </project>
配置文件application.yml文件为:
debug: false spring.aop.auto: true spring: application: name: data-producer cloud: consul: enabled: true host: localhost port: 8500 discovery: enabled: true register: true #是否将自身服务注册到consul中 hostname: 127.0.0.1 healthCheckPath: /actuator/health #服务健康检查地址 healthCheckInterval: 15s serviceName: ${spring.application.name} tags: test instanceId: ${spring.application.name}-${spring.cloud.client.ip-address}-${server.port} # 服务id
启动类DataProducerApplication
package com.test; import cn.hutool.core.convert.Convert; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.NetUtil; import cn.hutool.core.util.NumberUtil; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import java.util.Scanner; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @EnableDiscoveryClient @SpringBootApplication @EnableAutoConfiguration public class DataProducerApplication { public static void main(String[] args) { int port = 0; int defaultPort = 8080; int time = 5; Future<Integer> future = ThreadUtil.execAsync(() ->{ int p = defaultPort; System.out.println(String.format("请于%d秒钟内输入端口号, 推荐 8080 、 8081 或者 8082,超过%d秒将默认使用 %d", time, time, defaultPort)); Scanner scanner = new Scanner(System.in); while(true) { String strPort = scanner.nextLine(); if(!NumberUtil.isInteger(strPort)) { System.err.println("只能是数字"); } else { p = Convert.toInt(strPort); scanner.close(); break; } } return p; }); try{ port=future.get(time, TimeUnit.SECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e){ port = defaultPort; } if(!NetUtil.isUsableLocalPort(port)) { System.err.printf("端口%d被占用了,无法启动%n", port ); System.exit(1); } new SpringApplicationBuilder(DataProducerApplication.class).properties("server.port=" + port).run(args); } }
DataController处理每一个请求
package com.test.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController public class DataController { @RequestMapping("/**") public String get(HttpServletRequest request) { return String.format("实际响应地址:%s", request.getRequestURL().toString()); } }
使用LoadBalancerClient实现服务转发,即将服务映射到consul-producer服务
修改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"> <parent> <artifactId>springcloud-consul</artifactId> <groupId>com.test</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consul-consumer</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
配置文件application.yml
spring: application: name: data-consumer cloud: consul: host: 127.0.0.1 port: 8500 discovery: register: true hostname: 127.0.0.1 healthCheckPath: /actuator/health server: port: 8090 data-producer: data-producer
启动类DataConsumerApplication
package com.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class DataConsumerApplication { public static void main(String[] args) { SpringApplication.run(DataConsumerApplication.class, args); } }
DataConsumerController处理请求
package com.test.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.servlet.http.HttpServletRequest; @RestController public class DataConsumerController { @Value("${data-producer}") private String dataProducer; @Autowired private LoadBalancerClient loadBalancerClient; @RequestMapping("/data-api/**") public String test(HttpServletRequest request) { ServiceInstance serviceInstance = loadBalancerClient.choose(dataProducer); String result = new RestTemplate().getForObject(serviceInstance.getUri().toString() + request.getRequestURI().replace("data-api", ""), String.class); System.out.println(result); return result; } }
创建gateway-service模块,修改pom.xml增加gateway所需依赖
<?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"> <parent> <artifactId>springcloud-consul</artifactId> <groupId>com.test</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies> </project>
配置文件application.yml
server: port: 8100 spring: application: name: gateway-service cloud: gateway: routes: - id: data-service1 #请求 http://localhost:8100/data-service1/test会转发到data-producer服务, uri: lb://data-producer #在服务注册中心找服务名为 data-producer的服务, predicates: - Path=/data-service1/** filters: - StripPrefix=1 - id: data-service2 # 请求 http://localhost:8100/data-service2/test转发到 http://localhost:8080/test uri: http://localhost:8080 predicates: - Path=/data-service2/** filters: - StripPrefix=1 #前缀, 在当前路径匹配中表示去掉第一个前缀 /data-service2 consul: enabled: true host: localhost port: 8500 discovery: enabled: true register: false #是否将自身服务注册到consul中 hostname: 127.0.0.1 healthCheckPath: /actuator/health #服务健康检查地址 healthCheckInterval: 15s serviceName: ${spring.application.name} tags: test instanceId: ${spring.application.name}-${spring.cloud.client.ip-address}-${server.port} # 服务id
启动类GatewayServiceApplication
package com.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication public class GatewayServiceApplication { public static void main(String[] args) { SpringApplication.run(GatewayServiceApplication.class, args); } }
首先启动consul,启动两个DataProducerApplication实例,端口号为8080、8081, 启动DataConsumerApplication及GatewayServiceApplication
DataConsumerApplication服务
在浏览器输入http://localhost:8090/data-api/test, 访问DataConsumerApplication服务,输出结果为: “实际响应地址:http://127.0.0.1:8081/test” 或 "实际响应地址:http://127.0.0.1:8080/test"
GatewayServiceApplication服务
转发格式见application.yml文件
在浏览器中输入http://localhost:8100/data-service1/test, 访问GatewayServiceApplication同样 可以看到 有时访问8080端口的DataProducerApplication服务,有时访问8081端口的DataProducerApplication服务
在浏览器中输入http://localhost:8100/data-service2/test, 实际响应的是8080端口的DataProducerApplication服务,