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服務,