Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions QUARKUS_SUPPORT.md
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

--------------------------------
### 其他说明
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -109,10 +122,10 @@ private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
*/
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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ public static String genRandomStr() {
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;
}

/**
* 生成随机字符串
*
Expand All @@ -41,10 +54,10 @@ public static String genRandomStr() {
*/
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();
Expand Down