Skip to content
Merged
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
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,38 @@ jobs:
- name: Build spring-boot-2 samples with Maven
run: |
./mvnw -am -pl spring-boot-2/shardingsphere-jdbc-4.x-spring-sample,spring-boot-2/shardingsphere-jdbc-5.x-spring-sample -T1C -B -e clean test
test-native-ci:
if: github.repository == 'dynamic-datasource/dynamic-datasource-samples'
name: Native Test CI - GraalVM shard ${{ matrix.shard }} on ubuntu-latest
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5, 6, 7]
steps:
- uses: actions/checkout@v7
- name: Setup GraalVM
uses: graalvm/setup-graalvm@v1
with:
version: '25.3.4.1'
distribution: 'graalvm-community'
cache: 'maven'
# 各模块的 native / nativeTest 配置由 spring-boot-3 / spring-boot-4 父模块统一管理,
# 子模块声明插件即 opt-in。本地可用 `mvn -Pnative package` 构建 native image,
# 用 `mvn -PnativeTest test` 在 native image 中运行测试。CI 覆盖的模块清单按分片定义在
# 根 pom.xml 的 `native.test.modules.shard1..7` 属性中,矩阵并行执行以缩短总时长;
# 测试镜像在建 native image 时启用 quick build(`quickBuild`),依赖 Testcontainers
# 的模块使用 runner 自带的 Docker。以下模块未纳入该任务:
# beetlsql-sample 与 druid-sample 依赖的第三方库暂未提供 native 支持;
# tx-seata-sample 依赖的 Seata 在 AOT 处理阶段就会构造 GlobalTransactionScanner
# 并要求 Seata Server 可达,且其应用上下文在 AOT 类型预判定阶段存在 null Advisor
# 问题,故暂不纳入。
- name: Resolve native test modules
run: echo "NATIVE_TEST_MODULES=$(./mvnw -B -q help:evaluate -Dexpression=native.test.modules.shard${{ matrix.shard }} -DforceStdout)" >> "$GITHUB_ENV"
- name: Native test with Maven
run: |
./mvnw -B -e -PnativeTest clean test -pl "$NATIVE_TEST_MODULES"
lint-format-ci:
if: github.repository == 'dynamic-datasource/dynamic-datasource-samples'
name: Lint & Format CI
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ cd ./dynamic-datasource-samples/
因此 JDK 8 的 CI 任务直接对 `shardingsphere-jdbc-4.x-spring-sample` 与 `shardingsphere-jdbc-5.x-spring-sample` 执行 `clean test`;
JDK 17/21/25/27 的全量 `clean test` 同样覆盖这两个模块。

## GraalVM Native Image

native image 的构建与测试、Native Test CI 分片、Reachability Metadata 写法与上游 issue 跟进见
[docs/graalvm-native-image.md](./docs/graalvm-native-image.md)。

## 代码风格(Lint & Format)

CI 的 `Lint & Format CI` 任务在 JDK 21 下执行格式与静态检查,本地提交前请在**仓库根目录**执行:
Expand Down
88 changes: 88 additions & 0 deletions docs/graalvm-native-image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# GraalVM Native Image

`spring-boot-3` 与 `spring-boot-4` 下所有模块都已配置 native image 支持:插件版本由根
`pom.xml` 的 `native-maven-plugin.version` 统一指定,`native` / `nativeTest` profile
由版本线父模块统一管理(未继承 `spring-boot-starter-parent`,故显式定义,语义与官方一致),
子模块声明两个插件即 opt-in:

```shell
# 默认打出可执行 jar(HotSpot 运行)
./mvnw -B -e package -pl spring-boot-4/jdbc-template-sample
# 构建 GraalVM native image(需要 GraalVM,Boot 3 需 22.3+,Boot 4 需 25+;
# 也可用 `spring-boot:build-image` 走 Paketo 构建容器镜像)
./mvnw -B -e -Pnative package -pl spring-boot-4/jdbc-template-sample
# 在 native image 中运行测试
./mvnw -B -e -PnativeTest test -pl spring-boot-4/jdbc-template-sample
```

CI 的 `Native Test CI` 用 7 分片矩阵并行跑 `-PnativeTest test`(清单在根 `pom.xml` 的
`native.test.modules.shard1..7`,分片内串行;单模块本地跑
`mvn -PnativeTest clean test -pl <module>`)。测试镜像开 quick build(`-Ob`,勿与
`-H:+EnableFallbackCompilation` 同用)。未纳入的只有 `beetlsql-sample`(BeetlSQL 的
AOT 值序列化不支持)与 `tx-seata-sample`(Seata AOT 期要求 Server 可达、且有关闭后
依旧的 null Advisor 问题,见 apache/incubator-seata#8303)。

## Reachability Metadata 的写法

元数据一律以 JSON 写在模块的 `src/main/resources/META-INF/native-image/` 下,按
`<groupId>/<artifactId>/<version>` 分目录(样例自身目录不带版本号),不再使用 Java 的
`RuntimeHintsRegistrar`;只有 AOT 扫描结果驱动的逻辑才留在 Java 中
(如 MyBatis 模板的 `MyBatisBeanFactoryInitializationAotProcessor`):

```text
src/main/resources/META-INF/native-image/
├── com.baomidou/<sample-artifact>/ # 样例自身的资源与类(不带版本号)
├── com.baomidou/dynamic-datasource-creator/4.6.0/ # dynamic-datasource
├── com.baomidou/mybatis-plus/3.5.17/ # MyBatis-Plus
├── org.mybatis/mybatis/3.5.19/ # MyBatis
├── org.mybatis/mybatis-spring/4.1.0/ # MyBatis-Spring
└── com.mysql/mysql-connector-j/9.7.0/ # 其它依赖
```

两条硬规则:每个条目都带 `condition.typeReached`,键序为 `condition` → `type`/`glob` →
`reason` → 其余属性;条件类必须在该元数据首次被使用之前完成初始化,否则条目会被静默丢弃
(自条件对纯反射加载的类型永远不生效)。各目录的条件类见下表,改动后务必本地跑一遍
对应模块的 `-PnativeTest`。

| 目录 | `condition.typeReached` |
| --- | --- |
| `com.baomidou/dynamic-datasource-creator` | `com.baomidou.dynamic.datasource.creator.DataSourceProperty` |
| `com.baomidou/mybatis-plus` | `com.baomidou.mybatisplus.core.MybatisConfiguration` |
| `org.mybatis/mybatis` | `org.apache.ibatis.session.Configuration` |
| `org.mybatis/mybatis-spring` | `org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration` |
| `com.mysql/mysql-connector-j` | `com.mysql.cj.jdbc.Driver` |
| `p6spy/p6spy` | `com.p6spy.engine.spy.P6ModuleManager` |
| `org.springframework.cloud/spring-cloud-consul-core` | `org.springframework.cloud.consul.config.ConsulPropertySources` |
| `org.quartz-scheduler/quartz` | `com.baomidou.dynamic.datasource.creator.DataSourceProperty` |
| `org.apache.shardingsphere/shardingsphere-jdbc` | `org.apache.shardingsphere.driver.ShardingSphereDriver` |
| `com.github.ben-manes.caffeine/caffeine` | `com.github.benmanes.caffeine.cache.Caffeine` |
| `org.apache.seata/seata-all` | `org.apache.seata.spring.annotation.GlobalTransactionScanner` |
| 样例自身(`db/**`、`config*.yaml`、`HelloworldJob` 等) | 触发读取的依赖入口类(`DataSourceProperty`、`DockerClientFactory`、`ShardingSphereDriver` 等) |

`mvn -PnativeTest test` 变红时,按报错补条目即可(GraalVM 报错精确到类/字段);条件不生效
会被静默丢弃,改条件必跑一遍 nativeTest。常见坑:

- 按路径加载的资源(`db/schema.sql`、`config*.yaml`、`META-INF/services/**` 等)放
`resources.glob`;`DatasourceInitProperties` 等嵌套绑定类型缺了会导致建表静默跳过;
- `@MapperScan` 显式声明 `sqlSessionFactoryRef`,否则 AOT 丢 `AUTOWIRE_BY_TYPE` 装配;
- `spring-cloud-starter-bootstrap` 与 AOT 不兼容,改用 `spring.config.import`;
- MyBatis mapper 代理与实体由官方 `MyBatisNativeConfiguration` 模板的 AOT 处理器注册,
bean 名勿与 MP 自带的 `MyBatisPlusNativeImageConfiguration` 重复;
- `MySQLContainer` 的挂载问题见 testcontainers-java#7954(子类跳过挂载或用 `GenericContainer`);
- ShardingSphere 用 `config-native.yaml`(算法与行表达式限制见官方文档),另需显式依赖
`javax.transaction-api`;其自带元数据在 JDBC 用法下多不生效,以本仓库条目为准;
- JSON 只保留实测必需(agent 输出是超集,可删;与官方元数据重复的也删,如 caffeine 只留
官方缺的 `SIMS`;MP 3.5.14 的驱动条目不可删);flags 按实际访问收紧:实例化留
`allDeclaredConstructors`,绑定/反序列化再加 `allDeclaredMethods`,MyBatis 的 `MetaObject`
对(OGNL 调用)只要 `allDeclaredMethods`,caffeine 的 `SIMS` 用 `allDeclaredFields`,
`SqlSessionTemplate` 用 `allPublicMethods`,只做 `Class.forName` 的只登记类型;
`allPublicClasses`/`allDeclaredClasses` 不在 schema 里,勿用;
- `beetlsql-sample` 与 `tx-seata-sample` 都卡在 AOT 阶段,元数据尚未被 native 构建读取过:
seata 按 JVM 测试的 agent 实测裁剪,其余条目对齐其他模块的实测写法,待上游修复后用
nativeTest 复核;
- 每个条目用 `reason`(字符串数组)记录用途,符合 reachability-metadata-schema-v1.2.0,
当前 GraalVM 构建报 Unknown attribute 警告但忽略之、实测无影响,见 quarkusio/quarkus#49660。

## 上游 issue 跟进(TODO)

依赖上游修复的待办统一记录在 [upstream-todo.md](./upstream-todo.md),新增条目请写在那里。
63 changes: 63 additions & 0 deletions docs/upstream-todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 上游 issue 跟进(TODO)

依赖上游修复的待办。每条以 `TODO` 开头,写明上游 issue 与修复后本仓库要做的事;背景见
[graalvm-native-image.md](./graalvm-native-image.md)。

- TODO https://github.com/apache/incubator-seata/issues/8303 :Seata 修复 AOT 问题后,
把 `tx-seata-sample` 纳入 native CI,并用 nativeTest 复核按 JVM agent 裁剪的
`seata-all` 条目(agent 另采到 111 个尚未登记的类,届时按报错补)。
- TODO https://github.com/spring-projects/spring-framework/issues/37500 :Spring AOT
保留 `autowireMode` 后,去掉各模块 `@MapperScan` 的 `sqlSessionFactoryRef`
(逐模块去属性并跑 nativeTest 验证)。
- TODO https://github.com/baomidou/dynamic-datasource/issues/809 :DD 补上
`@NestedConfigurationProperty` 或自带元数据后,删除各模块
`dynamic-datasource-creator` 目录下的 `DatasourceInitProperties` 条目。
- TODO https://github.com/baomidou/dynamic-datasource/issues/811 :DD 把 mybatis-spring
改为 `compileOnly` 后,父 POM 对 mybatis-spring 的钉版本只剩统一 MP 模块(MP starter
自带 4.0.0)的作用,届时再决定去留,改动后跑 JVM 与 nativeTest 验证。
- TODO https://github.com/oracle/graal/issues/14708 :GraalVM parser 接受 `reason`
字段、不再报 Unknown attribute 后,确认各模块构建日志无新增警告。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/542 :官方收录
`seata-all` 后,对照精简 `tx-seata-sample` 的 `org.apache.seata/seata-all` 条目
(验证需等 apache/incubator-seata#8303 修复、该模块能跑 nativeTest)。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/9432 :官方补测
`mysql-connector-j` 8.0.31 元数据(覆盖到 9.7.0);关闭后升级 native-maven-plugin
(官方元数据随插件版本发布),若已含 `Driver` 与 `TimeZoneMapping.properties`,删除
`shardingsphere-jdbc-5.x-core-sample` 的 `com.mysql/mysql-connector-j` 目录并跑
nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/9437 :官方补测
`mybatis-plus` 3.5.3 元数据(覆盖到 3.5.17,目前是空的 `{}`);关闭后同样升级插件,
若已含 `MybatisXMLLanguageDriver` 与 `CompositeEnumTypeHandler`,删除各模块
`com.baomidou/mybatis-plus` 目录并跑 nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10906 :官方补上
caffeine 的 `SIMS`(`maximumSize` + `softValues`)后升级插件,删除
`shardingsphere-jdbc-5.x-core-sample` 的 `com.github.ben-manes.caffeine` 目录并跑
nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10907 :官方补上
OGNL 用到的 `SystemMetaObject`/`MetaObject` 与 `EnumTypeHandler(Class)` 构造器后升级
插件,删除 `mybatisplus3-sample`、`tx-local-sample` 的 `org.mybatis/mybatis` 目录并跑
nativeTest 验证(`tx-seata-sample` 的同类目录待 Seata 修复后再动)。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10908 :官方让
`tables_*.sql` 在 Spring Boot 建表初始化时已可用后升级插件,删除 `quartz-sample` 的
`org.quartz-scheduler` 目录并跑 nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10909 :官方收录
`dynamic-datasource-creator` 4.6.0 后升级插件,删除各模块
`com.baomidou/dynamic-datasource-creator` 目录并跑 nativeTest 验证(与上面 #809
哪个先落地都行)。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10910 :官方收录
`mybatis-spring` 4.1.0 后升级插件,删除各模块 `org.mybatis/mybatis-spring` 目录并跑
nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10911 :官方收录
`spring-cloud-consul-core` 5.0.3 后升级插件,删除 `config-consul-sample` 的
`org.springframework.cloud` 目录并跑 nativeTest 验证。
- TODO https://github.com/oracle/graalvm-reachability-metadata/issues/10912 :官方收录
`p6spy` 3.9.1 后升级插件,删除 `druid-sample` 的 `p6spy` 目录并跑 nativeTest 验证。
- TODO ShardingSphere 5.5.3 自带元数据(`shardingsphere-infra-reachability-metadata`)的问题:
SnakeYAML 反射构造的 7 个 YAML 配置类用的是自条件、不生效,`YamlSingleRuleConfiguration`
与 8 个 MySQL 解析器 SPI 类完全缺失;跟进地址 https://github.com/apache/shardingsphere/issues ,
目前暂未提 issue(提到 GRM 会让机器人为 65 个未收录的传递依赖各开一个 issue,故暂缓)。
修复后精简 `shardingsphere-jdbc-5.x-core-sample` 的 `org.apache.shardingsphere` 目录并跑
nativeTest 验证;其中条件为 `YamlEngine` 等的 4 条可能已与自带元数据重复,届时一并验证。
- TODO BeetlSQL 的 native 问题(`sqlManager` 的 `MySqlStyle` 不支持 AOT 值序列化),
跟进地址 https://gitee.com/xiandafu/beetlsql/issues ,目前暂无已知 issue;
问题修复后把 `beetlsql-sample` 纳入 native CI,并用 nativeTest 复核其元数据。
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@
<google-java-format.version>1.36.1</google-java-format.version>
<maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
<checkstyle.version>14.3.0</checkstyle.version>
<!--GraalVM Native Build Tools 全仓库统一使用最新版本,Boot 3 与 Boot 4 两条版本线共享;
如某条版本线需要钉住旧版本,可在对应 spring-boot-* 聚合模块中覆盖该属性。-->
<native-maven-plugin.version>1.1.14</native-maven-plugin.version>
<!--Native Test CI(见 .github/workflows/ci.yml)覆盖的模块清单,按分片拆分以并行执行,
逗号分隔;CI 通过 `mvn help:evaluate -Dexpression=native.test.modules.shardN` 读取后传给 `-pl`。-->
<native.test.modules.shard1>spring-boot-4/add-remove-datasource-sample,spring-boot-4/config-nacos-sample</native.test.modules.shard1>
<native.test.modules.shard2>spring-boot-4/load-datasource-from-jdbc-sample,spring-boot-4/shardingsphere-jdbc-5.x-core-sample</native.test.modules.shard2>
<native.test.modules.shard3>spring-boot-4/name-pattern-sample,spring-boot-4/quartz-sample</native.test.modules.shard3>
<native.test.modules.shard4>spring-boot-4/config-consul-sample,spring-boot-4/spel-sample</native.test.modules.shard4>
<native.test.modules.shard5>spring-boot-4/mybatis-sample,spring-boot-4/tx-local-sample</native.test.modules.shard5>
<native.test.modules.shard6>spring-boot-3/springboot3-sample,spring-boot-4/mybatisplus3-sample</native.test.modules.shard6>
<native.test.modules.shard7>spring-boot-4/jdbc-template-sample,spring-boot-4/druid-sample</native.test.modules.shard7>
</properties>

<modules>
Expand Down
Loading
Loading