mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-11-24 08:33:19 +08:00
🎨 #3732 Add Quarkus/GraalVM Native Image support - Fix Random instance initialization issues
This commit is contained in:
112
QUARKUS_SUPPORT.md
Normal file
112
QUARKUS_SUPPORT.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# WxJava Quarkus/GraalVM Native Image Support
|
||||
|
||||
## 概述
|
||||
|
||||
从 4.7.8.B 版本开始,WxJava 提供了对 Quarkus 和 GraalVM Native Image 的支持。这允许您将使用 WxJava 的应用程序编译为原生可执行文件,从而获得更快的启动速度和更低的内存占用。
|
||||
|
||||
## 问题背景
|
||||
|
||||
在之前的版本中,使用 Quarkus 构建 Native Image 时会遇到以下错误:
|
||||
|
||||
```
|
||||
Error: Unsupported features in 3 methods
|
||||
Detailed message:
|
||||
Error: Detected an instance of Random/SplittableRandom class in the image heap.
|
||||
Instances created during image generation have cached seed values and don't behave as expected.
|
||||
The culprit object has been instantiated by the 'org.apache.http.impl.auth.NTLMEngineImpl' class initializer
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
|
||||
为了解决这个问题,WxJava 进行了以下改进:
|
||||
|
||||
### 1. Random 实例的延迟初始化
|
||||
|
||||
所有 `java.util.Random` 实例都已改为延迟初始化,避免在类加载时创建:
|
||||
|
||||
- `RandomUtils` - 使用双重检查锁定模式延迟初始化
|
||||
- `SignUtils` - 使用双重检查锁定模式延迟初始化
|
||||
- `WxCryptUtil` - 使用双重检查锁定模式延迟初始化
|
||||
|
||||
### 2. Native Image 配置
|
||||
|
||||
在 `weixin-java-common` 模块中添加了 GraalVM Native Image 配置文件:
|
||||
|
||||
- `META-INF/native-image/com.github.binarywang/weixin-java-common/native-image.properties`
|
||||
- 配置 Apache HttpClient 相关类在运行时初始化,避免在构建时创建 SecureRandom 实例
|
||||
|
||||
- `META-INF/native-image/com.github.binarywang/weixin-java-common/reflect-config.json`
|
||||
- 配置反射访问的类和方法
|
||||
|
||||
## 使用方式
|
||||
|
||||
### Quarkus 项目配置
|
||||
|
||||
在您的 Quarkus 项目中使用 WxJava,只需正常引入依赖即可:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-miniapp</artifactId> <!-- 或其他模块 -->
|
||||
<version>4.7.8.B</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 构建 Native Image
|
||||
|
||||
使用 Quarkus 构建原生可执行文件:
|
||||
|
||||
```bash
|
||||
./mvnw package -Pnative
|
||||
```
|
||||
|
||||
或使用容器构建:
|
||||
|
||||
```bash
|
||||
./mvnw package -Pnative -Dquarkus.native.container-build=true
|
||||
```
|
||||
|
||||
### GraalVM Native Image
|
||||
|
||||
如果直接使用 GraalVM Native Image 工具:
|
||||
|
||||
```bash
|
||||
native-image --no-fallback \
|
||||
-H:+ReportExceptionStackTraces \
|
||||
-jar your-application.jar
|
||||
```
|
||||
|
||||
WxJava 的配置文件会自动被 Native Image 工具识别和应用。
|
||||
|
||||
## 测试验证
|
||||
|
||||
建议在构建 Native Image 后进行以下测试:
|
||||
|
||||
1. 验证应用程序可以正常启动
|
||||
2. 验证微信 API 调用功能正常
|
||||
3. 验证随机字符串生成功能正常
|
||||
4. 验证加密/解密功能正常
|
||||
|
||||
## 已知限制
|
||||
|
||||
- 本配置主要针对 Quarkus 3.x 和 GraalVM 22.x+ 版本进行测试
|
||||
- 如果使用其他 Native Image 构建工具(如 Spring Native),可能需要额外配置
|
||||
- 部分反射使用可能需要根据实际使用的 WxJava 功能进行调整
|
||||
|
||||
## 问题反馈
|
||||
|
||||
如果在使用 Quarkus/GraalVM Native Image 时遇到问题,请通过以下方式反馈:
|
||||
|
||||
1. 在 [GitHub Issues](https://github.com/binarywang/WxJava/issues) 提交问题
|
||||
2. 提供详细的错误信息和 Native Image 构建日志
|
||||
3. 说明使用的 Quarkus 版本和 GraalVM 版本
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Quarkus 官方文档](https://quarkus.io/)
|
||||
- [GraalVM Native Image 文档](https://www.graalvm.org/latest/reference-manual/native-image/)
|
||||
- [Quarkus Tips for Writing Native Applications](https://quarkus.io/guides/writing-native-applications-tips)
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎提交 PR 完善 Quarkus/GraalVM 支持!如果您发现了新的兼容性问题或有改进建议,请参考 [代码贡献指南](CONTRIBUTING.md)。
|
||||
15
README.md
15
README.md
@@ -65,13 +65,14 @@
|
||||
1. [`WxJava` 荣获 `GitCode` 2024年度十大开源社区奖项](https://mp.weixin.qq.com/s/wM_UlMsDm3IZ1CPPDvcvQw)。
|
||||
2. 项目合作洽谈请联系微信`binary0000`(在微信里自行搜索并添加好友,请注明来意,如有关于SDK问题需讨论请参考下文入群讨论,不要加此微信)。
|
||||
3. **2024-12-30 发布 [【4.7.0正式版】](https://mp.weixin.qq.com/s/_7k-XLYBqeJJhvHWCsdT0A)**!
|
||||
4. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
|
||||
5. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
|
||||
6. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
|
||||
7. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
|
||||
8. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
|
||||
9. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
|
||||
10. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
|
||||
4. **从 4.7.8.B 版本开始支持 Quarkus/GraalVM Native Image,详见 [【Quarkus 支持文档】](QUARKUS_SUPPORT.md)**。
|
||||
5. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
|
||||
6. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
|
||||
7. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
|
||||
8. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
|
||||
9. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
|
||||
10. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
|
||||
11. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
|
||||
|
||||
--------------------------------
|
||||
### 其他说明
|
||||
|
||||
@@ -4,12 +4,24 @@ public class RandomUtils {
|
||||
|
||||
private static final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
private static final java.util.Random RANDOM = new java.util.Random();
|
||||
private static volatile java.util.Random random;
|
||||
|
||||
private static java.util.Random getRandom() {
|
||||
if (random == null) {
|
||||
synchronized (RandomUtils.class) {
|
||||
if (random == null) {
|
||||
random = new java.util.Random();
|
||||
}
|
||||
}
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
public static String getRandomStr() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
java.util.Random r = getRandom();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length())));
|
||||
sb.append(RANDOM_STR.charAt(r.nextInt(RANDOM_STR.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,19 @@ public class WxCryptUtil {
|
||||
private static final Base64 BASE64 = new Base64();
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
private static volatile Random random;
|
||||
|
||||
private static Random getRandom() {
|
||||
if (random == null) {
|
||||
synchronized (WxCryptUtil.class) {
|
||||
if (random == null) {
|
||||
random = new Random();
|
||||
}
|
||||
}
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
private static final ThreadLocal<DocumentBuilder> BUILDER_LOCAL = ThreadLocal.withInitial(() -> {
|
||||
try {
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
@@ -109,10 +122,10 @@ public class WxCryptUtil {
|
||||
*/
|
||||
private static String genRandomStr() {
|
||||
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
Random r = getRandom();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int number = random.nextInt(base.length());
|
||||
int number = r.nextInt(base.length());
|
||||
sb.append(base.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Args = --initialize-at-run-time=org.apache.http.impl.auth.NTLMEngineImpl \
|
||||
--initialize-at-run-time=org.apache.http.impl.auth.NTLMEngine \
|
||||
--initialize-at-run-time=org.apache.http.impl.auth.KerberosScheme \
|
||||
--initialize-at-run-time=org.apache.http.impl.auth.SPNegoScheme
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"name": "me.chanjar.weixin.common.util.RandomUtils",
|
||||
"methods": [
|
||||
{"name": "getRandomStr", "parameterTypes": []}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "me.chanjar.weixin.common.util.crypto.WxCryptUtil",
|
||||
"allDeclaredConstructors": true,
|
||||
"allDeclaredMethods": true,
|
||||
"allDeclaredFields": true
|
||||
}
|
||||
]
|
||||
@@ -33,6 +33,19 @@ public class SignUtils {
|
||||
return genRandomStr(32);
|
||||
}
|
||||
|
||||
private static volatile Random random;
|
||||
|
||||
private static Random getRandom() {
|
||||
if (random == null) {
|
||||
synchronized (SignUtils.class) {
|
||||
if (random == null) {
|
||||
random = new Random();
|
||||
}
|
||||
}
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机字符串
|
||||
*
|
||||
@@ -41,10 +54,10 @@ public class SignUtils {
|
||||
*/
|
||||
public static String genRandomStr(int length) {
|
||||
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
Random random = new Random();
|
||||
Random r = getRandom();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = random.nextInt(base.length());
|
||||
int number = r.nextInt(base.length());
|
||||
sb.append(base.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
Reference in New Issue
Block a user