1 相关背景介绍
1.1 Spring Cloud Gateway介绍
Spring Cloud Gateway 是一个基于 Spring Framework 和 Spring Boot 的 API 网关服务,它利用了 Spring WebFlux 来提供响应式非阻塞式Web请求处理能力。它的核心功能是路由,即根据请求的特定规则将请求转发到后端服务,同时提供了一系列跨领域关注点的处理,如安全认证、监控、限流等。
Spring Cloud Gateway 还提供了多种内置的 GatewayFilter
工厂,如 AddRequestHeader
、AddRequestParameter
、CircuitBreaker
、RequestRateLimiter
等,用于修改请求和响应、实现断路器功能、限流等。此外,还可以自定义 GatewayFilter
来满足特定的需求 5。
1.2 Solon介绍
Java “纯血国产”应用开发框架。从零开始构建,有自主的标准规范与开放生态。
有以下特点。
- 轻量性:Solon 的内核非常小,仅有 0.1MB,最小接口开发单位为 0.2MB 10。
- 高性能:在 HTTP helloworld 测试中,Solon 能够达到 12 万的 QPS,表现出色 10。
- 多种开发模式:支持 RPC、REST API、MVC、Job、Micro service、WebSocket 和 Socket 等多种开发模式 10。
- 代码操控自由度:Solon 强调代码的自由操控,以满足特定的业务需求 10。
- 生态插件:拥有 150 多个生态插件,可以满足各种场景开发 12。
- 国产框架适配:Solon 支持国产框架适配,为应用软件国产化提供支持 12。
- 启动速度:相较于 Spring Boot 和 Spring Cloud,Solon 的启动速度快 5 到 10 倍 13。
- QPS 和内存占用:QPS 高 2 到 3 倍,运行时内存节省 1/3 到 1/2 13。
- 支持 JDK 版本:Solon 支持 JDK 8 至 JDK 222,以及 GraalVM native image 13。
- 编程语言支持:Solon 不仅限于 Java,还支持 Kotlin 等多种编程语言 14。
2 项目代码
2.1 gateway项目代码
首先引入依赖
<dependencies>
<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>
</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>
编写配置文件
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: "solon project" # id 不要重复即可
uri: http://localhost:8123 # 代理地址
predicates:
- Path=/solon/** # 断言 满足则使用当前路由规则
filters:
- RewritePath=/solon/?(?<segment>.*), /$\{segment} # 路径重写过滤 http://localhost/solon/ -> http://localhost:8123/
- id: "qq" # id
uri: https://www.qq.com # 代理地址
predicates:
- Query=url,qq # 请求参数?url=qq时匹配 请求参数过滤器
server:
port: 80
正常启动项目即可
2.2 Solon 项目代码
引入依赖
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>2.8.5</version>
<relativePath/>
</parent>
<packaging>jar</packaging>
<description>Demo project for Solon</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-api</artifactId>
</dependency>
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon.logging.logback</artifactId>
</dependency>
<!-- 开启 http_2 使用-->
<!-- <dependency>-->
<!-- <groupId>org.noear</groupId>-->
<!-- <artifactId>solon.boot.undertow</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.noear</groupId>
<artifactId>solon-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>tencent</id>
<url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
编写主启动
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
//import org.noear.solon.boot.http.HttpServerConfigure;
@SolonMain
public class App {
public static void main(String[] args) {
// Solon.start(App.class, args,app->{
// app.onEvent(HttpServerConfigure.class, e -> {
// e.enableHttp2(true); //开启 http_2
// });
// });
Solon.start(App.class,args);
}
}
编写控制层
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
@Controller
public class HelloSolonController {
@Mapping
public String solon() {
return "Hello Solon!";
}
@Get
@Mapping("/hello")
public String hello(@Param(defaultValue = "world") String name) {
return String.format("Hello %s!", name);
}
}
启动Solon 项目 可以感觉到启动速度很快
访问 地址 http://localhost:8123
2.3 gateway代理
访问 http://localhost/solon
这里是我们写的路由匹配规则生效了,代理到solon的服务了
也可以验证我们写的另一个路由匹配规则
http://localhost?url=qq
说明gateway是按我们的规则去实现的
3 排错过程
3.1 前置条件
在通过spring gateway 代理的时候错误把依赖引入错误
路由配置基本一样
spring:
application:
name: gateway
cloud:
gateway:
mvc:
routes:
- id: "solon project" # id 不要重复即可
uri: http://localhost:8123 # 代理地址
predicates:
- Path=/solon/** # 断言 满足则使用当前路由规则
filters:
- RewritePath=/solon/?(?<segment>.*), /$\{segment} # 路径重写过滤 http://localhost/solon/ -> http://localhost:8123/
- id: "qq" # id
uri: https://www.qq.com # 代理地址
predicates:
- Query=url,qq # 请求参数?url=qq时匹配 请求参数过滤器
启动项目
这时可以正常代理qq网页
但是代理solon项目时发生了错误
3.2 debug调试
通过idea的异常断点创建对应的异常断点监视快速定位到错误代码行
再次请求找到出错行号进入 request.newAbstractRequest(); 方法中找到出错的方法
这里发现他的type被解析成 HTTP_2 了所以返回null
这里引入支持http2依赖
<!-- 开启 http_2 使用-->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon.boot.undertow</artifactId>
</dependency>
启动类添加配置
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
import org.noear.solon.boot.http.HttpServerConfigure;
@SolonMain
public class App {
public static void main(String[] args) {
Solon.start(App.class, args,app->{
app.onEvent(HttpServerConfigure.class, e -> {
e.enableHttp2(true); //开启 http_2
});
});
// Solon.start(App.class,args);
}
}
这样再次请求就可以了,不过后来我发现不配置也可以!!!知道引入依赖就好了,所以可能解析的时候出错了,再次查看源码和断点
这里就是解析type的方法看着好像没有什么问题不过不知道为什么和protocol不一样
不过我用访问了spring boot项目是可以正常访问的
solon代码https://gitee.com/zhong-liuyang/solon-quickstart.git
总结spring cloud gateway代理solon还是可行的,就是spring cloud gateway mvc代理时出现了错误。不过网关通常还是使用spring cloud gateway 毕竟底层是netty+webflux响应式编程。