最近接了一个需求,要把一些现有的golang微服务对接到老平台的spring cloud微服务框架中。这些golang微服务提供了一些proto+grpc接口,对接老平台目的就是,想要快速复用这些后端的业务能力,这样一来,只需要涉及交互的设计和前端编码的工作,后端不需要用java重写一遍造轮子,并且这些golang微服务是之前上过线的,所以稳定性和准确性都有保证。
老平台的架构和这个极精简版类似:
所以,我就把重心放在如何将golang微服务接入到spring cloud gateway里,然后要满足以下几个需求:
- 复用spring cloud gateway路由和负载均衡能力,能将url正确路由到golang微服务内,当然前提是golang微服务需要暴露出restful api
- 复用spring cloud gateway的身份认证能力
- java和golang微服务可以互相进行rpc调用,比如golang微服务可以通过rpc获取某个租户的信息
通过在网上的一番调研,最终锁定了spring-cloud-alibaba-sidecar和grpc-gateway这两个组件,整体的对接思路如下,下面开始搞个demo验证一下:
1. Spring Cloud Gateway环境搭建
1.1 mvn安装
wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz | |
tar -zxvf apache-maven-3.9.6-bin.tar.gz | |
vim /etc/profile | |
/* | |
尾部追加 | |
export MAVEN_HOME=/usr/local/apache-maven-3.9.6 | |
export PATH=$MAVEN_HOME/bin:$PATH | |
*/ | |
source /etc/profile | |
mvn -v | |
/* | |
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae) | |
Maven home: /usr/download/apache-maven-3.9.6 | |
Java version: 21.0.2, vendor: Oracle Corporation, runtime: /usr/lib/jvm/jdk-21-oracle-x64 | |
Default locale: en_US, platform encoding: UTF-8 | |
OS name: "linux", version: "3.10.0-1160.el7.x86_64", arch: "amd64", family: "unix" | |
*/ | |
vim conf/settings.xml | |
/* <!-- mirror标签页下新增 | |
<mirror> | |
<id>huaweicloud</id> | |
<mirrorOf>central</mirrorOf> | |
<name>huaweicloud</name> | |
<url>https://mirrors.huaweicloud.com/repository/maven/</url> | |
</mirror> | |
*/ |
1.2 jdk安装
wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm | |
rpm -ivh jdk-21_linux-x64_bin.rpm | |
javac -version | |
/* | |
javac 21.0.2 | |
*/ | |
java --version | |
/* | |
java 21.0.2 2024-01-16 LTS | |
Java(TM) SE Runtime Environment (build 21.0.2+13-LTS-58) | |
Java HotSpot(TM) 64-Bit Server VM (build 21.0.2+13-LTS-58, mixed mode, sharing) | |
*/ |
1.4 spring cloud gateway
git clone git@github.com:spring-guides/gs-gateway.git | |
cd gs-gateway/initial | |
vim pom.xml | |
/* | |
pom修改如下: | |
<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> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>3.2.0</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> | |
<groupId>com.example</groupId> | |
<artifactId>gs-gateway</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<name>gs-gateway</name> | |
<description>Demo project for Spring Boot</description> | |
<properties> | |
<java.version>17</java.version> | |
<spring-cloud.version>2023.0.0-RC1</spring-cloud.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-gateway</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-loadbalancer</artifactId> | |
</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> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-alibaba-dependencies</artifactId> | |
<version>2022.0.0.0-RC1</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> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.9.0</version> | |
<configuration> | |
<source>2.1</source> | |
<target>2.1</target> | |
<verbose>true</verbose> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
<repositories> | |
<repository> | |
<id>spring-milestones</id> | |
<name>Spring Milestones</name> | |
<url>https://repo.spring.io/milestone</url> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</repository> | |
</repositories> | |
</project> | |
*/ | |
mvn install | |
java -jar gs-gateway-0.0.1-SNAPSHOT.jar --debug | |
curl http://localhost:8080/get | |
/* | |
{ | |
"args": {}, | |
"headers": { | |
"Accept": "*/*", | |
"Connection": "close", | |
"Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:56207\"", | |
"Hello": "World", | |
"Host": "httpbin.org", | |
"User-Agent": "curl/7.54.0", | |
"X-Forwarded-Host": "localhost:8080" | |
}, | |
"origin": "0:0:0:0:0:0:0:1, 73.68.251.70", | |
"url": "http://localhost:8080/get" | |
} | |
*/ |
2. Nacos安装
wget https://github.com/alibaba/nacos/releases/download/2.3.0/nacos-server-2.3.0.tar.gz | |
tar -zxvf nacos-server-2.3.0.tar.gz | |
bin/startup.sh -m standalone |
3. Golang和Java启动web服务
mvn archetype:generate | |
vim pom.xml | |
/* | |
修改如下: | |
<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> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>3.2.0</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> | |
<groupId>javaweb</groupId> | |
<artifactId>javaweb</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<name>javaweb</name> | |
<description>Demo project for Spring Boot</description> | |
<properties> | |
<java.version>17</java.version> | |
<spring-cloud.version>2023.0.0-RC1</spring-cloud.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.12</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-web</artifactId> | |
<version>2.6.3</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-contract-stub-runner</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> | |
<dependency> | |
<groupId>com.alibaba.cloud</groupId> | |
<artifactId>spring-cloud-alibaba-dependencies</artifactId> | |
<version>2022.0.0.0-RC1</version> | |
<type>pom</type> | |
<scope>import</scope> | |
</dependency> | |
</dependencies> | |
</dependencyManagement> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-maven-plugin</artifactId> | |
<version>2.6.3</version> | |
</plugin> | |
</plugins> | |
</build> | |
<repositories> | |
<repository> | |
<id>spring-milestones</id> | |
<name>Spring Milestones</name> | |
<url>https://repo.spring.io/milestone</url> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</repository> | |
</repositories> | |
</project> | |
*/ | |
vim bootstrap.yml | |
/* | |
新增如下: | |
server: | |
port: 10001 | |
spring: | |
profiles: | |
active: dev | |
application: | |
name: javaweb | |
cloud: | |
nacos: | |
config: | |
file-extension: yaml | |
group: dev | |
server-addr: 127.0.0.1:8848 | |
discovery: | |
auto-register: true | |
server-addr: 127.0.0.1:8848 | |
locator: | |
enabled: true | |
lower-case-service-id: true | |
*/ | |
vim App.java | |
/* | |
修改java文件如下: | |
package javaweb; | |
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; | |
import org.springframework.context.annotation.Bean; | |
@EnableDiscoveryClient | |
@RestController | |
@RequestMapping("/java-service-1") | |
@SpringBootApplication | |
public class App { | |
public static void main(String[] args) { | |
SpringApplication.run(App.class, args); | |
} | |
@GetMapping("/hello") | |
public String hello() { | |
return "[java]Hello, World!we server in port 10001"; | |
} | |
@Bean | |
public TomcatServletWebServerFactory servletContainer(){ | |
return new TomcatServletWebServerFactory(8022) ; | |
} | |
} | |
*/ | |
java -jar target/javaweb-0.0.1-SNAPSHOT.jar --spring.config.location=/usr/code/javaweb/bootstrap.yml --spring.cloud.nacos.config.import-check.enabled=false | |
curl http://localhost:10001/java-service-1/hello |
wget https://golang.google.cn/dl/go1.21.6.darwin-amd64.tar.gz | |
tar -zxvf go1.21.6.linux-amd64.tar.gz -C /usr/local/ | |
vim /etc/profile | |
/* | |
尾部追加: | |
export GOROOT=/usr/local/go | |
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH | |
*/ | |
source /etc/profile | |
go version | |
/* | |
go version go1.21.6 linux/amd64 | |
*/ | |
vi main.go | |
/* | |
新建main.go如下: | |
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"log" | |
"net/http" | |
) | |
func main() { | |
http.HandleFunc("/golang-service/hello", helloHandler) | |
http.HandleFunc("/golang-service/health", healthHandler) | |
log.Println("Go 微服务已启动,监听端口 10002...") | |
log.Fatal(http.ListenAndServe(":10002", nil)) | |
} | |
func helloHandler(w http.ResponseWriter, r *http.Request) { | |
fmt.Fprintf(w, "[golang] hello world!") | |
} | |
func healthHandler(w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Content-Type", "application/json") | |
actuator := make(map[string]string) | |
actuator["status"] = "UP" | |
_ = json.NewEncoder(w).Encode(actuator) | |
log.Println("[golang] i'm alive!...") | |
} | |
*/ | |
go run main.go | |
//2024/02/03 10:43:21 Go 微服务已启动,监听端口 10002... | |
curl http://localhost:10002/golang-service/hello |
3. Alibaba Sidecar
git clone git@github.com:alibaba/spring-cloud-alibaba.git | |
cd spring-cloud-alibaba/spring-cloud-alibaba-examples/spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example/ | |
vi src/main/resources/application.yml | |
/* | |
server: | |
port: 8070 | |
spring: | |
cloud: | |
nacos: | |
username: 'nacos' | |
password: 'nacos' | |
discovery: | |
server-addr: 127.0.0.1:8848 | |
group: DEFAULT_GROUP | |
gateway: | |
discovery: | |
locator: | |
enabled: true | |
loadbalancer: | |
nacos: | |
enabled: true | |
ribbon: | |
enabled: false | |
application: | |
name: golangweb | |
sidecar: | |
# 异构微服务的IP | |
ip: 127.0.0.1 | |
# 异构微服务的端口 | |
port: 10002 | |
# 异构微服务的健康检查URL | |
health-check-url: http://localhost:10002/golang-service/health | |
management: | |
endpoint: | |
health: | |
show-details: always | |
*/ | |
mvn install | |
java -jar target/spring-cloud-alibaba-sidecar-nacos-example-2022.0.0.0.jar |
大家注意看这个10002是golang微服务的端口,心跳检查也持续进行,灰常完美。
4. Gateway 路由配置修改
# vim bootstrap.yml | |
server: | |
port: 10003 | |
spring: | |
profiles: | |
active: dev | |
application: | |
name: gy-gateway | |
cloud: | |
gateway: | |
discovery: | |
auto-register: true | |
server-addr: 127.0.0.1:8848 | |
locator: | |
enabled: true | |
# 是否使用service-id的小写,默认是大写 | |
lower-case-service-id: true | |
routes: | |
- id: javawebsvr | |
uri: lb://javaweb | |
predicates: | |
- Path=/java-service-1/** # 断言,路径相匹配的进行路由(注意**为通配符) | |
filters: | |
- StripPrefix=1 | |
- id: golangsvr | |
# uri: http://127.0.0.1:10002/ 都行 | |
uri: lb://golangweb | |
predicates: | |
- Path=/golang-service/** # 断言,路径相匹配的进行路由(注意**为通配符) | |
filters: | |
- StripPrefix=1 | |
curl http://localhost:10003/golang-service/golang-service/hello | |
curl http://localhost:10003/java-service-1/java-service-1/hello |
5. Java调用Golang微服务
在之前的javaweb工程的基础上改了一些东西: | |
vi bootstrap.yml | |
/* | |
server: | |
port: 10011 | |
*/ | |
vim App.java | |
/* | |
package javaweb; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.web.client.RestTemplate; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.cloud.client.loadbalancer.LoadBalanced; | |
import org.springframework.cloud.client.discovery.DiscoveryClient; | |
import org.springframework.cloud.client.ServiceInstance; | |
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; | |
import java.util.List; | |
public class App { | |
public static void main(String[] args) { | |
SpringApplication.run(App.class, args); | |
} | |
public String hello() { | |
return "[java]Hello, World!we server in port 10001"; | |
} | |
public RestTemplate restTemplate() { | |
return new RestTemplate(); | |
} | |
private RestTemplate restTemplate; | |
private DiscoveryClient discoveryClient; | |
public String hellogolang() { | |
List<String> services = discoveryClient.getServices(); | |
for (String service : services) { | |
System.out.println("**service**:"+service); | |
} | |
List<ServiceInstance> instances = discoveryClient.getInstances("golangweb"); | |
for (ServiceInstance instance : instances) { | |
System.out.println(instance.getInstanceId()+"\t"+instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri()); | |
String url = "http://"+instance.getHost() + ":" + instance.getPort() + "/golang-service/hello"; | |
return restTemplate.getForObject(url, String.class); | |
} | |
return "ha"; | |
} | |
} | |
*/ | |
java -jar target/javaweb-0.0.1-SNAPSHOT.jar --spring.config.location=/usr/code/javaweb/bootstrap.yml --spring.cloud.nacos.config.import-check.enabled=false --debug --spring.main.allow-circular-references=true --spring.main.web-application-type=reactive |
Reference
https://sca.aliyun.com/zh-cn/blog/spring-boot-to-spring-cloud-best-practice
https://blog.csdn.net/lucky_ykcul/article/details/105219891
https://blog.csdn.net/it_sunwz/article/details/115271506
https://blog.csdn.net/u011019141/article/details/78458566
https://blog.csdn.net/zsf_join/article/details/99819845
https://github.com/spring-guides/gs-gateway
https://spring.io/guides/gs/gateway/
https://www.jianshu.com/p/c4952ef14660
https://blog.csdn.net/llm_hao/article/details/122856895
https://blog.csdn.net/weixin_44102521/article/details/117689297
https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
https://javahungry.blogspot.com/2019/05/solved-no-main-manifest-attribute-in-jar.html
https://blog.csdn.net/zsf_join/article/details/99819845
https://blog.csdn.net/hkl_Forever/article/details/129353742
https://blog.csdn.net/m4330187/article/details/122182282