graalvm+spring-cloud-gateway打造又快又小的类nginx本地网关

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

网关是微服务架构的入口外网请求通过网关转发到独立的微服务。项目一般会经过多个环境的测试最终发布到生产。一个http请求如http://public_host/api/v1/some_service/some_path?a=b&c=d会先经过公网域名然后通过nginx匹配路径/api/v1/**把请求转发到相应的网关网关再转发给对应服务。

本地开发时一般会采用idea的Tools->HTTP Client->Create Request in HTTP Client工具来调试本地接口http://localhost:8080/some_path?a=b&c=d发布测试环境后用postman来调试测试环境接口(http://public_host/api/v1/some_service/some_path?a=b&c=d)也就是说本地开发时在idea中写的接口测试文档等发布到测试环境后又要再写一遍。如果本地有一个网关提供基本的转发功能就能打通本地和测试环境的隔阂一份接口测试文档多个环境使用。

本地搭一个网关方式有很多

  1. idea起一个spring-cloud-gateway项目优点是简单易操作可定制缺点启动速度慢占用内存高
  2. 下载一个nginx服务器本地起一个nginx服务用于转发请求也比较简单内存也不高缺点要阅读文档不能修改代码来自定义
  3. 用graalvm把spring-cloud-gateway编译成本地exespringcloud项目学习成本低转发逻辑可以自定义按需修改本地镜像启动快占用内存低。

实践环节

准备工作

  1. 安装graalvm以及native-image
  2. 安装Visual Studio 2022 Developer Command Prompt v17.4.3

创建spring-cloud-gateway项目

添加下面几个依赖项

  1. GraalVM Native Support
  2. Spring Reactive Web
  3. Gateway
  4. Spring Boot Actuator监控端点可选

完整的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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.github.xxx</groupId>
    <artifactId>cloudgateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloudgateway</name>
    <description>cloudgateway</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.0</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</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>io.projectreactor</groupId>
            <artifactId>reactor-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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件配置了跨域和一个路由调整了日志级别代码如下

server:
  port: 9090
spring:
  application:
    name: cloudgateway
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        cors-configurations:
          '[/**]':
            maxAge: 3600
            allowCredentials: false
            allowedOrigins: "*"
            allowedMethods: GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE
            allowedHeaders: "*"
            exposedHeaders: Content-Length,content-disposition
      routes:
        - id: path_route
          uri: http://127.0.0.1:8080
          predicates:
            - Path=/api/v1/**
          filters:
            - StripPrefix=3
logging:
  level:
    org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory: trace

https://start.spring.io网站创建的项目模板有一个HELP.md提供了很多有用的信息。

开始编译

打开Visual Studio 2022 Developer Command Prompt v17.4.3切换到项目目录执行

 mvnw.cmd native:compile -Pnative -DskipTests

估计有10来分钟先喝杯咖啡。

查看结果

项目target目录下生成了一个cloudgateway.exe文件双击打开正常运行。

仿照上面流程又编译了一个普通的spring-boot项目只包含一个接口和actutor端点名叫demo.exe双击打开正常运行。

在浏览器输入一个请求发给网关转发发现报错如下

Caused by: java.lang.NullPointerException: null
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.stringToList(ResolverConfigurationImpl.java:69) ~[na:na]
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.loadConfig(ResolverConfigurationImpl.java:136) ~[na:na]
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.nameservers(ResolverConfigurationImpl.java:159) ~[na:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.serversForUrls(DnsContextFactory.java:149) ~[cloudgateway2.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.getContext(DnsContextFactory.java:81) ~[cloudgateway2.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.urlToContext(DnsContextFactory.java:120) ~[cloudgateway2.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.getInitialContext(DnsContextFactory.java:64) ~[cloudgateway2.exe:na]
        at java.naming@17.0.5/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:732) ~[cloudgateway2.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305) ~[cloudgateway2.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.init(InitialContext.java:236) ~[cloudgateway2.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.<init>(InitialContext.java:208) ~[cloudgateway2.exe:na]
        at java.naming@17.0.5/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:130) ~[cloudgateway2.exe:na]
        at io.netty.resolver.dns.DirContextUtils.addNameServers(DirContextUtils.java:49) ~[na:na]
        at io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.<clinit>(DefaultDnsServerAddressStreamProvider.java:53) ~[na:na]
        ... 145 common frames omitted

百度了半天找到了报错原因原来是HttpClient没有配置默认的地址解析器。配置方法如下

@Bean
public HttpClientCustomizer httpClientResolverCustomizer() {
    return httpClient -> httpClient.resolver(DefaultAddressResolverGroup.INSTANCE);
}

再次编译结束双击运行正常转发请求也正常。

内存对比

exe运行内存如下
占用内存
idea运行内存如下
idea占用内存

至此graalvm编译spring-cloud-gateway就算完成了。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: nginxSpring