在maven环境中使用GraalVM来构建本地原生应用程序(一)构建本地可执行文件

文章目录

  • 前言
  • 一、GraalVM安装
  • 二、初步使用
  • 三、踩坑记录
    • 1、JSON转换问题
    • 2、反射、资源、jni的调用问题
    • 3、HTTPS调用问题
    • 4、Linux下CPU架构问题
    • 5、Linux下GLIBC版本的问题
    • 6、部分Windows系统无法缺少相关的库文件
  • 总结


前言

随着Java17的更新,jdk又推出了一个GraalVM平台,关于GraalVM的相关资料大家可以去官网了解,点击这里进入官网。
什么是GraalVM?我感觉用一句话来解释就是:把Java程序编译成本机的可执行的二进制代码。之前的Java一直运行在JVM平台上,所谓的Java跨平台性,其实完全依赖的是JVM的跨平台性,我们发布的所有Java程序,都必须安装一个JVM的平台,这样在操作性上还是有很多不便。
其次最近几年流行的云原生应用多半会是未来微服务的趋势,Java作为微服务重要的成员,原生应用貌似迫在眉睫。
GraalVM目前还没有JVM成熟,各大Java生态也在推行,springboot3.0和quarkus也都在积极支持,说明GraalVM或许是Java开发的另外一条路子。
正好目前我再开发一个项目,这个项目对性能的要求很高,于是尝试了用GraalVM来构建,经过测试完全能满足目前的需求,但在使用过程中还是有很多不方便的地方,而且GraalVM对编码的要求很高,下面我给大家分享在使用过程中踩到的一些坑,我的开发环境是springboot生态,关于quarkus生态大家可以自行去研究。


一、GraalVM安装

首先进入官网进行下载,选择jdk版本和平台,我这里使用JDK17,如下图:
在这里插入图片描述
下载完后解压,会得到一个文件夹如:graalvm-jdk-17.0.9+11.1,进入到文件夹:
在这里插入图片描述
我这里结构如下,Home里面其实就是jdk环境,这是我们要修改JAVA_HOME环境变量。将JAVA_HOME的路径改到我们下载的这里,然后查看Java环境:

java -version

如下:

java version "17.0.9" 2023-10-17 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 17.0.9+11.1 (build 17.0.9+11-LTS-jvmci-23.0-b21)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.9+11.1 (build 17.0.9+11-LTS-jvmci-23.0-b21, mixed mode, sharing)

如果有带GraalVM的信息,说明安装成功,另外我们也可以直接运行native-image:

native-image

输出:

Please specify options for native-image building or use --help for more info.

说明已经安装成功

二、初步使用

下面我们创建一个springboot的项目,这里springboot我们选择3.2.2,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 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.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>test-sb-native</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-sb-native</name>
    <description>test-sb-native</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <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>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

这里最重要的是加入了native-maven-plugin这个插件,然后我们写点简单的代码方便我们测试:

package org.example.testsbnative;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class TestSbNativeApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSbNativeApplication.class, args);
    }

    @RequestMapping("/test")
    public Object test(){
        return "hello native";
    }
}

然后我们执行打包命令,这里的打包命令需要这样写:

mvn clean -DskipTests native:compile -Pnative

过程比较漫长,与电脑的性能有关系,等待打包结束,我们看到有如下信息输出表示成功:

------------------------------------------------------------------------------------------------------------------------
Top 10 origins of code area:                                Top 10 object types in image heap:
  16.18MB java.base                                            9.83MB byte[] for code metadata
   5.16MB tomcat-embed-core-10.1.18.jar                        3.83MB byte[] for java.lang.String
   4.66MB svm.jar (Native Image)                               2.95MB java.lang.Class
   3.90MB java.xml                                             2.92MB java.lang.String
   2.42MB jackson-databind-2.15.3.jar                          2.69MB byte[] for general heap data
   2.03MB spring-core-6.1.3.jar                                1.35MB byte[] for embedded resources
   1.84MB spring-boot-3.2.2.jar                                1.05MB byte[] for reflection metadata
 894.52kB spring-web-6.1.3.jar                               742.17kB com.oracle.svm.core.hub.DynamicHubCompanion
 829.04kB jackson-core-2.15.3.jar                            455.69kB c.o.svm.core.hub.DynamicHub$ReflectionMetadata
 792.90kB spring-beans-6.1.3.jar                             438.81kB java.util.HashMap$Node
   7.50MB for 69 more packages                                 3.75MB for 3235 more object types
------------------------------------------------------------------------------------------------------------------------

下面我们看打包的结果,进入到项目target目录:
在这里插入图片描述
这里我们看到不但生成了jar包,还有一个可执行文件,如果你是Windows,这里就是一个exe格式的文件。
下面我来运行这个文件,Windows下直接双击运行,macOS下执行:

./target/test-sb-native

运行结果:

2024-01-31T19:44:21.945+08:00  INFO 26199 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-01-31T19:44:21.945+08:00  INFO 26199 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 27 ms
2024-01-31T19:44:21.965+08:00  INFO 26199 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 12345 (http) with context path ''
2024-01-31T19:44:21.965+08:00  INFO 26199 --- [           main] o.e.t.TestSbNativeApplication            : Started TestSbNativeApplication in 0.058 seconds (process running for 0.065)

说明运行成功,我们在访问:http://localhost:12345/test

在这里插入图片描述

运行正常。

三、踩坑记录

1、JSON转换问题

下面我们改造一下项目,代码如下:

package org.example.testsbnative;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.Serializable;

@SpringBootApplication
@RestController
public class TestSbNativeApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSbNativeApplication.class, args);
    }

    @RequestMapping("/test")
    public Object test(){
        return "hello native";
    }
    @RequestMapping("/json")
    public Object json(){
        return new User("1","user1");
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class User implements Serializable{
        private String id;
        private String name;
    }
}

我们增加一个URL,来返回json格式的数据,然后打包并运行,并访问http://localhost:12345/json,发现返回如下错误:

curl http://localhost:12345/json
{"timestamp":"2024-01-31T12:40:40.066+00:00","status":406,"error":"Not Acceptable","path":"/json"}

后台收到这样一个警告:

2024-01-31T20:39:21.449+08:00  WARN 29757 --- [io-12345-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]

导致这样的问题,是因为我们返回json需要使用到Java的序列化和反序列化机制,Java的序列化机制是利用的JVM的特性来完成的。

解决方式:在启动类上加一个@RegisterReflectionForBinding(TestSbNativeApplication.User.class)注解,把需要序列化的类全部加入RegisterReflectionForBinding注解中,这里我们加入配置后重新打包并运行,就能正常返回:

curl http://localhost:12345/json
{"id":"1","name":"user1"}

2、反射、资源、jni的调用问题

因为这三个问题的解决方式是一样的,所以这里我们统一来处理,我们先改造一下代码:

@RequestMapping("/rf")
public Object ex() throws Exception{
    Field roleField = ReflectionUtils.findField(Role.class,"name");
    assert roleField != null;
    ReflectionUtils.makeAccessible(roleField);
    Role role=new Role();
    roleField.set(role,"role1");

    Field userField = ReflectionUtils.findField(User.class,"name");
    assert userField != null;
    ReflectionUtils.makeAccessible(userField);
    User user=new User();
    userField.set(user,"user1");

    return List.of(role.getName(),user.getName());
}
@RequestMapping("/rs")
public Object rs() throws Exception{
    try (InputStream inputStream=getClass().getResourceAsStream("/config.properties")){
        assert inputStream != null;
        return IOUtils.toByteArray(inputStream);

    }catch (Exception e){
        return "发生异常:"+e.getMessage();
    }
}
@RequestMapping("/oshi")
public Object oshi() throws Exception{
    StringBuffer buffer=new StringBuffer();
    buffer.append(OshiUtils.getOs().getFamily());
    buffer.append(OshiUtils.getSystem().getHardwareUUID());
    buffer.append(OshiUtils.getSystem().getModel());
    buffer.append(OshiUtils.getMemory().getAvailable());
    return buffer;
}

1、我们首先加入对反射的应用

2、加入对额外资源的应用,我们加了一个配置文件

3、我们加入oshi来检测对JNI的应用

我们先打包然后运行,这一切都是正常的,然后我们来测试:

反射:

curl http://localhost:12345/rf
{"timestamp":"2024-02-01T02:05:16.308+00:00","status":500,"error":"Internal Server Error","path":"/rf"}

资源:

curl http://localhost:12345/rs
发生异常:inputStream

JNI调用:

curl http://localhost:12345/oshi
{"timestamp":"2024-02-01T02:07:03.492+00:00","status":500,"error":"Internal Server Error","path":"/oshi"}

全部无法使用,这下完犊子了,我们一个项目不可能不用反射,也不可能不使用其他资源文件,当然jni也是我们常用的东西。下面我们就来解决这个问题。

导致这样的问题,也是GraalVM的特性决定的,关于这方面的解释,大家可以去官网上查看,同时要解决大家也可以参照这里

就是要把需要用到的资源和反射的类都要进行申明,我感觉这种方式不可取,一个项目中要把你所用的所有资源和反射的类都统计出来,貌似很难,而且我们用的外部jar包里面,别人用没用怎么清楚啊。

如果要进行自动统计,这里我们就要使用Java里面的-agent机制,关于agent模式,相关资料我也不多介绍了,我们具体讲解操作,

第一步:我们先将项目进行普通打包

mvn clean -DskipTests package

第二步:使用agent模式来启动jar包

java -agentlib:native-image-agent=config-output-dir=native  -jar target/sb-test.jar

运行这个命令后,会在项目下产生一个native的文件夹,这里就会吧用到的资源,反射,jni的信息全部收集起来。

但这里有个瑕疵,它并不会自动收集,而是需要人工手动来触发,比如我们想要收集刚才的反射用的资源,我们必须手动调用curl http://localhost:12345/rf,让那部分代码执行,agent模式只会收集执行过的代码,对应没有执行过的代码就不会收集。这也是个大坑,这就会要求我们在打包时,必须要保证我们所有的用到这三种技术的代码块都能执行一次,
不然就会漏掉。

第三步:执行代码

为了方便,我们这里写一个Junit的单元,把我们用到过的反射、资源、jni部分的代码保都能执行一次,这个例子比较简单,代码如下:

package org.example.testsbnative;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;

class TestSbNativeApplicationTests {
    private static HttpClient client = HttpClient.newBuilder().build();

    @Test
    void rf() throws Exception{
        System.out.println(get("http://localhost:12345/rf").body());
        System.out.println(get("http://localhost:12345/rs").body());
        System.out.println(get("http://localhost:12345/oshi").body());
    }

    private static HttpResponse<String> get(String url) throws Exception{
        URI uri=URI.create(url);
        HttpRequest.Builder builder=HttpRequest.newBuilder()
                .timeout(Duration.ofSeconds(8))
                .uri(uri)
                .GET();
        HttpRequest request = builder.build();
        return client.send(request, HttpResponse.BodyHandlers.ofString());
    }
}

或者大家可以手动来执行,执行结果如下:

["role1","user1"]
config1=config1
config2=config2

macOS607881B4-CF4B-555B-872C-C7DDAAD9E799MacBookPro16,116471416832

说明程序是没问题,而且在JVM平台下都能正常运行.

第四步:结束agent

agent模式需要我们手动结束,直接按ctrl+c,然后我们检查项目目录下就产生了一个native文件夹:
在这里插入图片描述
大家可以打开看下里面的内容

第五步:进行native打包

在进行native打包的时候,我们需要修改插件的配置:

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <configuration>
        <mainClass>org.example.testsbnative.TestSbNativeApplication</mainClass>
        <agentResourceDirectory>${basedir}/native</agentResourceDirectory>
        <imageName>sb-native</imageName>
        <fallback>false</fallback>
        <verbose>true</verbose>
        <quickBuild>true</quickBuild>
        <metadataRepository>
            <enabled>true</enabled>
        </metadataRepository>
    </configuration>
</plugin>

修改完成后执行命令:

mvn clean -DskipTests native:compile -Pnative

打包成功,然后启动运行,再来测试这三个接口:

反射测试:

curl http://localhost:12345/rf  
["role1","user1"]

资源文件测试:

curl http://localhost:12345/rs  
config1=config1
config2=config2

jni测试:

curl http://localhost:12345/oshi
macOS607881B4-CF4B-555B-872C-C7DDAAD9E799MacBookPro16,116963862528

最终发现,一切正常

3、HTTPS调用问题

如果在我们的项目中需要调用外部的https接口,需要在编译时加入–enable-url-protocols参数,具体配置如下:

<buildArgs>
    <arg>--enable-url-protocols=http,https</arg>
</buildArgs>

大家可以自行测试一下

4、Linux下CPU架构问题

默认情况下GraalVM打包对CPU架构的支持采用native模式,就是如果我是在AMD64架构的机器上编译,那编译的程序就只能在AMD64的CPU上运行,在AArch64上编译的就只能在AArch64的CPU上运行,这给跨平台带来很大不便,要解决这个方案加入下面配置:

<buildArgs>
    <arg>--enable-url-protocols=http,https</arg>
    <arg>-march=compatibility</arg>
</buildArgs>

改成兼容模式,经过测试,基本上没什么问题

5、Linux下GLIBC版本的问题

这里最明显的例子就是,我再centos7上面编译的程序,然后放到centos6上去运行,结果出现下面的错误:

./sb-native: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./sb-native)
./sb-native: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./sb-native)

具体原因是centos6上的GLIBC版本过低导致,要解决这个问题,可以下载我这里的的补丁文件,进行逐个安装后即可

6、部分Windows系统无法缺少相关的库文件

在部分Windows服务器上,运行本地包时,会报找不到XXXX,这是因为缺少相关的库,点击这里下载补丁,双击安装即可。

经过测试,大部分Windows操作系统都能正常运行,但唯有win7是个例外。应该是绝大部分win7都无法运行,目前还没找到原因,我甚至用go打包后的执行文件,在win7上都无法运行。


总结

1、总的来说GraalVM目前还不是很成熟,要想达到c/c++/go那样的编译效果,还差的很远。

2、对应 反射、资源、jni的调用问题的解决方式Java agent是一种解决方式,另外也可以使用springboot提供的注解来解决,但是这样要自己去枚举项目中所用到的所有的资源和反射的类,具体的注解可以参照:@ImportRuntimeHints、@RegisterReflectionForBinding

3、但相信GraalVM会越来越完善,毕竟这对Java开发者来说,编译二进制本地程序已经没被卡脖子了。

4、对应比较大或者业务逻辑比较复杂的Java项目,建议不要尝试GraalVM,这里面的坑估计踩不完。

5、用GraalVM编译的程序,在CPU占用和内存占用相对在JVM平台上来说,真的是指数级的提高,后面我会给大家分享相关的测试。

6、由于是编译本机二进制,所以失去了跨平台特性,Java的一次编译到处运行的优势不再。比如我想在Windows下运行,那我必须要到Windows下去编译才行。

7、目前比较通用的做法是在docker下编译,后面我给大家分享在docker如何编译。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/371778.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【lesson10】高并发内存池细节优化

文章目录 大于256KB的大块内存申请问题大于256KB的大块释放申请问题使用定长内存池脱离使用new释放对象时优化为不传对象大小完整版代码Common.hObjectPool.hThreadCache.hThreadCache.cppConcurrentAlloc.hCentralCache.hCentralCache.cppPageCache.hPageCache.cpp 大于256KB的…

SpringBoot中数据库的连接及Mybatis的配置和使用

目录 1 在pom.xml中引入相关依赖 2 对数据库进行配置 2.1 配置application.yml 2.2 idea连接数据库 (3.2.1有用到) 3 Mybatis的使用 3.1 测试文件的引入 3.2 使用 3.2.1 使用注解(有小技巧(✪ω✪)) 3.2.2 使用动态sql 1 在pom.xml中引入相关依赖 <dependencies&g…

【DDD】学习笔记-EAS 的整体架构实践

为了得到系统的整体架构&#xff0c;我们还欠缺什么呢&#xff1f;所谓“架构”&#xff0c;是“以组件、组件之间的关系、组件与环境之间的关系为内容的某一系统的基本组织结构&#xff0c;以及指导上述内容设计与演化的原则”。之所以要确定系统的组件、组件关系以及设计与演…

线上编程答疑解惑回顾,初学编程中文编程在线屏幕共享演示

线上编程答疑解惑回顾&#xff0c;初学编程中文编程在线屏幕共享演示 一、学编程过程中有不懂的怎么办&#xff1f; 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载——常用工具下载——编…

基于深度学习的SSVEP分类算法简介

基于深度学习的SSVEP分类算法简介 1、目标与范畴2、深度学习的算法介绍3、参考文献 1、目标与范畴 稳态视觉诱发电位&#xff08;SSVEP&#xff09;是指当受试者持续注视固定频率的闪光或翻转刺激时&#xff0c;在大脑枕-额叶区域诱发的与刺激频率相关的电生理信号。与P300、运…

【C/C++ 12】C++98特性

目录 一、命名空间 二、缺省参数 三、函数重载 四、引用 五、内联函数 六、异常处理 一、命名空间 在C/C项目中&#xff0c;存在着大量的变量、函数和类&#xff0c;这些变量、函数和类都存在于全局作用域中&#xff0c;可能会导致命名冲突。 使用命名空间的目的就是对…

Gateway API 实践之(七)FSM Gateway 的负载均衡算法

FSM Gateway 流量管理策略系列&#xff1a; 故障注入黑白名单访问控制限速重试会话保持健康检查负载均衡算法TLS 上游双向 TLS 在微服务和 API 网关架构中&#xff0c;负载均衡是至关重要的&#xff0c;它确保每个服务实例都能平均地处理请求&#xff0c;同时也为高可用性和故…

2024.2.4 模拟实现 RabbitMQ —— 实现核心类

目录 引言 创建 Spring Boot 项目 编写 Exchange 实体类 编写 Queue 实体类 编写 Binding 实体类 编写 Message 实体类 引言 上图为模块设计图 此处实现核心类为了简便&#xff0c;我们引用 Lombok&#xff08;可点击下方链接了解 Lombok 的使用&#xff09; IDEA 配置 L…

【npm】修改npm全局安装包的位置路径

问题 全局安装的默认安装路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm&#xff0c;缓存路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm_cache&#xff08;其中admin为自己的用户名&#xff09;。 由于默认的安装路径在C盘&#xff0c;太浪费C盘内存啦&#…

C语言之数据在内存中的存储

目录 1. 整数在内存中的存储2. 大小端字节序和字节序判断什么是大小端&#xff1f;为什么有大小端&#xff1f;练习1练习2练习3练习4练习5练习6 3. 浮点数在内存中的存储浮点数存的过程浮点数取得过程练习题解析 1. 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们已经…

算法学习——华为机考题库7(HJ41 - HJ45)

算法学习——华为机考题库7&#xff08;HJ41 - HJ45&#xff09; HJ41 称砝码 描述 现有n种砝码&#xff0c;重量互不相等&#xff0c;分别为 m1,m2,m3…mn &#xff1b; 每种砝码对应的数量为 x1,x2,x3…xn 。现在要用这些砝码去称物体的重量(放在同一侧)&#xff0c;问能称…

前端 - 基础 列表标签 - 自定义列表 详解

使用场景 &#xff1a; 常用于对术语或名词进行解释和描述&#xff0c;定义列表的列表前没有任何项目符号。 在 HTML 标签中&#xff0c; < dl > 标签用于定义 描述列表 &#xff08; 或定义列表 &#xff09; 该标签会与 <dt> ( 定义项目/名字 ) 和 <dd…

从0搭建react+ts+redux+axios+antd项目

文章目录 一、安装及初始化二、TypeScript配置三、Webpack配置四、Prettier统一编码风格五、使用less六、Antd 安装及使用七、添加redux及使用八、添加Router及配置九、安装axios十、echarts按需引入 本文介绍了如何用creat-react-app脚手架搭建一个react项目的基本结构&#x…

UE4 C++ 静态加载类和资源

静态加载类和资源&#xff1a;指在编译时加载&#xff0c;并且只能在构造函数中编写代码 .h //增加所需组件的头文件 #include "Components/SceneComponent.h" //场景组件 #include "Components/StaticMeshComponent.h" //静态网格体组件 #include &qu…

VS2019+CAXACAD2023二次开发教程(一、环境搭建)

前言 CAXACAD2023的二次开发相关文件和库都在installpath\CRX\的文件夹下。 CAXACAD2023的默认开发环境是VS2019,如果是用VS2019的环境话,可以直接安装"installpath\CRX\Wizard\CRXWizard_VS2019.exe"这个插件,安装好后就可以一键新建的项目,新建的项目会自动帮…

【漏洞复现】EPON上行A8-C政企网关信息泄露漏洞

Nx01 产品简介 EPON上行A8-C政企网关是一款终端产品&#xff0c;提供企业网络解决方案。 Nx02 漏洞描述 EPON上行A8-C政企网关敏感信息泄露漏洞&#xff0c;攻击者通过敏感信息泄露获取管理员密码。 Nx03 产品主页 fofa-query: "ZXECS" && title"Web…

蓝桥杯每日一题----区间dp

前言 暂时没啥好说的&#xff0c;直接进入正题吧 引入 涂色PAINT 读题发现要求的是使一段区间满足要求的最小操作次数&#xff0c;考虑用动态规划去做。 第一步&#xff1a;考虑缩小规模&#xff0c;这里的规模其实就是区间长度&#xff0c;那么dp数组应该可以表示某个区间&…

certificate has expired错误解决

npm ERR! request to https://registry.npm.taobao.org/nodemon failed, reason: certificate has expired错误解决 npm在安装依赖包时出现以下错误。 作为最后的手段&#xff0c;你可以配置npm忽略SSL证书验证。这不是一个推荐的解决方案&#xff0c;因为它会降低安全性&…

window 镜像---负载篇

前提&#xff1a;需要修改window的powershell执行脚本的策略 步骤&#xff1a;以管理员身份打开powershell&#xff0c;执行 Get-ExecutionPolicy查看当前执行策略&#xff0c;若返回值是Restricted&#xff0c;需执行Set-ExecutionPolicy RemoteSigned powershell 版本信息&am…

计算机网络第6章(应用层)

6.1、应用层概述 我们在浏览器的地址中输入某个网站的域名后&#xff0c;就可以访问该网站的内容&#xff0c;这个就是万维网WWW应用&#xff0c;其相关的应用层协议为超文本传送协议HTTP 用户在浏览器地址栏中输入的是“见名知意”的域名&#xff0c;而TCP/IP的网际层使用IP地…