Quarkus框架: Stork实现服务网关功能
简介:
在SpringCloud框架中,我们会使用Gateway作为服务网关 Nacos作为配置中心和注册中心 ,那么如果基于Quarkus框架,这个基于Kubernetes原生的JAVA应用开发框架,我们怎么实现类似Gateway的功能,又怎么样搭建类似于SpringCloud这种体系的微服务框架呢?
个人说明:
以下代码和图片仅仅由本人结合Quarkus官网和个人研究以及查阅相关资料独立研发而成,如果有对Quarkus框架初学和感兴趣的,可以支持参考,也请多多评论,指出不足,分享技术和交流。
项目技术
本项目名称:Quarkus-Gateway Quarkus版本:3.15.2 Maven版本:3.9.8 JDK版本: dragonwell-21
项目依赖(pom文件)
<?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>pers.lys.framework</groupId>
<artifactId>quarkus-gateway</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.15.2</quarkus.platform.version>
<jjwt.version>0.12.6</jjwt.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.3.1</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-core-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-stork</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.stork</groupId>
<artifactId>stork-service-discovery-consul</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-consul-client</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
<!-- <version>3.11.0</version>-->
</dependency>
<!-- jackson 序列化-->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
</dependency>
<!-- 解决java.time.LocalDateTime相关的问题-->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.1-jre</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
<goal>native-image-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
</project>
路由转发代理
package pers.lys.gateway.router.system;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import java.io.InputStream;
/**
* @Describe: 路由:服务名 quarkus-system
* @Date: 2024/12/24-16:44
* @Author: LYS
*/
@RegisterRestClient(baseUri = "stork://quarkus-system")
@Path("/api/system")//quarkus-system服务 对外暴露上下文前缀地址
public interface SystemRouter {
/**
* @Describe: GET请求
* @Date: 2024/12/24-17:02
* @Author: LYS
*/
@GET
@Path("/{path:.*}")
@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
@Produces(MediaType.MEDIA_TYPE_WILDCARD)
Response getRout(@PathParam("path") String path, @QueryParam("queryParam") String queryParam, @HeaderParam("X-User-Info") String baseAcUserDOStr);
/**
* @Describe: DELETE请求
* @Date: 2024/12/24-17:02
* @Author: LYS
*/
@DELETE
@Path("/{path:.*}")
@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
@Produces(MediaType.MEDIA_TYPE_WILDCARD)
Response deleteRout(@PathParam("path") String path, @QueryParam("queryParam") String queryParam, @HeaderParam("X-User-Info") String baseAcUserDOStr);
/**
* @Describe: POST请求
* @Date: 2024/12/24-17:02
* @Author: LYS
*/
@POST
@Path("/{path:.*}")
@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
@Produces(MediaType.MEDIA_TYPE_WILDCARD)
Response postRout(@PathParam("path") String path, InputStream inputStream,@HeaderParam("X-User-Info") String baseAcUserDOStr);
/**
* @Describe: PUT请求:整体更新
* @Date: 2024/12/24-16:47
* @Author: LYS
*/
@PUT
@Path("/{path:.*}")
@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
@Produces(MediaType.MEDIA_TYPE_WILDCARD)
Response putRout(@PathParam("path") String path, InputStream inputStream, @HeaderParam("X-User-Info") String baseAcUserDOStr);
/**
* @Describe: PATCH请求:部分更新
* @Date: 2024/12/24-16:47
* @Author: LYS
*/
@PATCH
@Path("/{path:.*}")
@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
@Produces(MediaType.MEDIA_TYPE_WILDCARD)
Response patchRout(@PathParam("path") String path, InputStream inputStream, @HeaderParam("X-User-Info") String baseAcUserDOStr);
}
路由转发实际地址
package pers.lys.gateway.router.system;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.InputStream;
/**
* @Describe: 路由服务发现:
* @Date: 2024/12/24-16:56
* @Author: LYS
*/
@Path("/quarkus/system") //quarkus-system服务 实际服务地址
public class SystemRouterFound implements SystemRouter {
@RestClient
SystemRouter systemRouter;
@Override
public Response getRout(String path, String queryParam, String baseAcUserDOStr) {
return systemRouter.getRout(path, queryParam, baseAcUserDOStr);
}
@Override
public Response deleteRout(String path, String queryParam, String baseAcUserDOStr) {
return systemRouter.deleteRout(path, queryParam, baseAcUserDOStr);
}
@Override
public Response postRout(String path, InputStream inputStream, String baseAcUserDOStr) {
return systemRouter.postRout(path, inputStream,baseAcUserDOStr);
}
@Override
public Response putRout(String path, InputStream inputStream, String baseAcUserDOStr) {
return systemRouter.putRout(path, inputStream, baseAcUserDOStr);
}
@Override
public Response patchRout(String path, InputStream inputStream, String baseAcUserDOStr) {
return systemRouter.patchRout(path, inputStream, baseAcUserDOStr);
}
}
演示转发效果
1.启动Quarkus-Gateway项目
项目Quarkus-Gateway 端口:19009
项目注册中心使用的Consul ,在网关项目中,我们使用stork自动注册发现功能来实现网关转发功能
其中在application.properties文件中配置如下
我这边还有一个目标服务:Quarkus-System项目,端口是9000,启动如下:
此时我们看Quarkus-System服务中 提供了一个接口名为单点登录,其中上下文路径是/api/system/login
这个api/system和“路由转发代理”标题下的Path是一致的 ,@RegisterRestClient(baseUri = “stork://quarkus-system”) 这个就是目标服务注册到Consul的服务名
这样我们本来访问 http://127.0.0.1:19000/api/system/login的地址,经过网关转发只需要访问 http://127.0.0.1:19009/quarkus/system/login ,我们测试验证下,转发成功。