This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git


The following commit(s) were added to refs/heads/main by this push:
     new 3c8cb3c  Config data serialization, module system wiring, JVM boot 
verification
3c8cb3c is described below

commit 3c8cb3c181f13a6f06456361aeeeeee5606fac6d
Author: Wu Sheng <[email protected]>
AuthorDate: Fri Feb 20 21:58:55 2026 +0800

    Config data serialization, module system wiring, JVM boot verification
    
    - Precompiler serializes parsed config POJOs to META-INF/config-data/*.json
    - Add 3 replacement config loaders: MeterConfigs, Rules, LALConfigs
      (load from JSON instead of filesystem YAML)
    - Add library-module-for-graalvm: ModuleDefine replacement with direct
      prepare() overload, bypassing ServiceLoader discovery
    - Simplify FixedModuleManager to use ModuleDefine.prepare() directly,
      delete ModuleWiringBridge
    - Add configuration.has() guards for 6 optional modules in startup
    - Centralize all dependency versions in root pom.xml
    - Add debug logging for per-script MAL/LAL/filter loading ([count/total])
    - Add docker-compose with all 4 BanyanDB data paths
    - Add make shutdown target, SHA-256 staleness test for replacements
    - Verify full JVM boot: 38 modules, 620 OAL + 1250 MAL + 7 LAL scripts
    - Update DISTRO-POLICY.md: 23 replacement classes across 13 modules
---
 .gitignore                                         |   1 +
 CLAUDE.md                                          |   3 +
 CONFIG-INIT-IMMIGRATION.md                         |   2 +-
 DISTRO-POLICY.md                                   |  43 +++-
 LAL-IMMIGRATION.md                                 |  17 ++
 MAL-IMMIGRATION.md                                 |  24 +++
 Makefile                                           |  23 ++-
 build-tools/precompiler/pom.xml                    |  12 ++
 .../server/buildtools/precompiler/Precompiler.java | 145 ++++++++++++--
 docker/docker-compose.yml                          |  27 +++
 oap-graalvm-server/pom.xml                         |  39 +++-
 .../server/graalvm/GraalVMOAPServerStartUp.java    |  28 ++-
 .../server/library/module/FixedModuleManager.java  |  47 +++--
 .../server/library/module/ModuleWiringBridge.java  | 120 -----------
 .../server/library/util/YamlConfigLoaderUtils.java |  34 ++--
 .../graalvm/ReplacementClassStalenessTest.java     | 125 ++++++++++++
 .../resources/replacement-source-sha256.properties |  31 +++
 .../agent-analyzer-for-graalvm/pom.xml             |   5 +
 .../provider/meter/config/MeterConfigs.java        |  82 ++++++++
 .../pom.xml                                        |  14 +-
 .../oap/server/library/module/ModuleDefine.java    | 167 ++++++++++++++++
 .../log-analyzer-for-graalvm/pom.xml               |   5 +
 .../skywalking/oap/log/analyzer/dsl/DSL.java       |   5 +-
 .../oap/log/analyzer/provider/LALConfigs.java      |  86 ++++++++
 .../meter-analyzer-for-graalvm/pom.xml             |   5 +
 .../skywalking/oap/meter/analyzer/dsl/DSL.java     |   5 +-
 .../oap/meter/analyzer/dsl/FilterExpression.java   |   5 +-
 .../oap/meter/analyzer/prometheus/rule/Rules.java  | 113 +++++++++++
 oap-libs-for-graalvm/pom.xml                       |   1 +
 .../server-core-for-graalvm/pom.xml                |   1 +
 .../core/config/HierarchyDefinitionService.java    |  68 +++----
 .../server/core/hierarchy/HierarchyService.java    | 222 +++++++++++++++++++++
 pom.xml                                            |  71 +++++++
 33 files changed, 1340 insertions(+), 236 deletions(-)

diff --git a/.gitignore b/.gitignore
index 776c98c..310d0b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 # Build output
 target/
 dependency-reduced-pom.xml
+*.class
 
 # IDE
 .idea/
diff --git a/CLAUDE.md b/CLAUDE.md
index d39fe4b..8dffa54 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -39,6 +39,9 @@ JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal mvn 
-pl build-tools/pr
 JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal mvn -pl 
oap-graalvm-server test
 ```
 
+## Git Commit Rules
+- **No Co-Authored-By**: Do not add `Co-Authored-By` lines to commit messages.
+
 ## Selected Modules
 - **Storage**: BanyanDB
 - **Cluster**: Standalone, Kubernetes
diff --git a/CONFIG-INIT-IMMIGRATION.md b/CONFIG-INIT-IMMIGRATION.md
index d16ac16..49d15d0 100644
--- a/CONFIG-INIT-IMMIGRATION.md
+++ b/CONFIG-INIT-IMMIGRATION.md
@@ -15,7 +15,7 @@ config-related reflection.
 
 ## Problem
 
-In `ModuleWiringBridge.wireAndPrepare()` and in `BanyanDBConfigLoader`,
+In `ModuleDefine.prepare()` and in `BanyanDBConfigLoader`,
 `copyProperties()` iterates property names, looks up fields by name via
 reflection, and sets them:
 
diff --git a/DISTRO-POLICY.md b/DISTRO-POLICY.md
index 4e53997..60b5c34 100644
--- a/DISTRO-POLICY.md
+++ b/DISTRO-POLICY.md
@@ -109,12 +109,12 @@ MAL expressions rely on `propertyMissing()` for sample 
name resolution and `Expa
 **Details**: [CONFIG-INIT-IMMIGRATION.md](CONFIG-INIT-IMMIGRATION.md)
 
 ### What Was Built
-- `FixedModuleManager` — direct module/provider construction, no SPI
-- `ModuleWiringBridge` — wires all selected modules/providers
-- `GraalVMOAPServerStartUp` — entry point
+- `FixedModuleManager` — direct module/provider construction via 
`ModuleDefine.prepare()` overload, no SPI
+- `GraalVMOAPServerStartUp` — entry point with `configuration.has()` guards 
for 6 optional modules
 - `application.yml` — simplified config for selected providers
 - `ConfigInitializerGenerator` — build-time tool that scans config classes and 
generates `YamlConfigLoaderUtils` replacement
-- `YamlConfigLoaderUtils` — same-FQCN replacement (8th replacement class) 
using type-dispatch + setter/VarHandle instead of reflection
+- `YamlConfigLoaderUtils` — same-FQCN replacement using type-dispatch + 
setter/VarHandle instead of reflection
+- `ModuleDefine` — same-FQCN replacement (`library-module-for-graalvm`) adding 
`prepare(ModuleManager, ModuleProvider, ...)` overload for direct provider 
wiring without ServiceLoader
 
 ---
 
@@ -133,17 +133,18 @@ Each upstream JAR that has replacement classes gets a 
corresponding `*-for-graal
 
 `oap-graalvm-server` depends on `*-for-graalvm` JARs instead of originals. 
Original upstream JARs are forced to `provided` scope via 
`<dependencyManagement>` to prevent transitive leakage.
 
-### 19 Same-FQCN Replacement Classes Across 12 Modules
+### 23 Same-FQCN Replacement Classes Across 13 Modules
 
 **Non-trivial replacements (load pre-compiled assets from manifests):**
 
 | Module | Replacement Classes | Purpose |
 |---|---|---|
+| `library-module-for-graalvm` | `ModuleDefine` | Add `prepare()` overload for 
direct provider wiring (bypasses ServiceLoader) |
 | `server-core-for-graalvm` | `OALEngineLoaderService`, `AnnotationScan`, 
`SourceReceiverImpl`, `MeterSystem`, `CoreModuleConfig`, 
`HierarchyDefinitionService` | Load from manifests instead of 
Javassist/ClassPath; config with @Setter; Java-backed closures instead of 
GroovyShell |
 | `library-util-for-graalvm` | `YamlConfigLoaderUtils` | Set config fields via 
setter instead of reflection |
-| `meter-analyzer-for-graalvm` | `DSL`, `FilterExpression` | Load pre-compiled 
MAL Groovy scripts from manifest |
-| `log-analyzer-for-graalvm` | `DSL`, `LogAnalyzerModuleConfig` | Load 
pre-compiled LAL scripts; config with @Setter |
-| `agent-analyzer-for-graalvm` | `AnalyzerModuleConfig` | Config with @Setter |
+| `meter-analyzer-for-graalvm` | `DSL`, `FilterExpression`, `Rules` | Load 
pre-compiled MAL Groovy scripts from manifest; load rule data from JSON 
config-data manifests |
+| `log-analyzer-for-graalvm` | `DSL`, `LogAnalyzerModuleConfig`, `LALConfigs` 
| Load pre-compiled LAL scripts; config with @Setter; load LAL config data from 
JSON config-data manifests |
+| `agent-analyzer-for-graalvm` | `AnalyzerModuleConfig`, `MeterConfigs` | 
Config with @Setter; load meter config data from JSON config-data manifests |
 
 **Config-only replacements (add `@Setter` for reflection-free config):**
 
@@ -239,6 +240,12 @@ packaged in JARs. The YAML source files are not needed at 
runtime.
 **Total: 89 files** consumed at build time, producing ~1285 pre-compiled 
classes
 and ~1254 Groovy scripts stored in JARs.
 
+Additionally, the precompiler serializes parsed config POJOs as JSON manifests 
in
+`META-INF/config-data/` (7 JSON files for meter-analyzer-config, otel-rules,
+envoy-metrics-rules, log-mal-rules, telegraf-rules, zabbix-rules, and lal). 
These
+provide the runtime "wiring" data (metric prefixes, rule names, expression 
lookup
+keys) that replacement loader classes use instead of filesystem YAML access.
+
 ### Not Included (upstream-only)
 
 | File | Reason |
@@ -253,7 +260,7 @@ and ~1254 Groovy scripts stored in JARs.
 - [x] Set up Maven + Makefile in this repo
 - [x] Build skywalking submodule as a dependency
 - [x] Set up GraalVM JDK 25 in CI (`.github/workflows/ci.yml`)
-- [x] Create a JVM-mode starter with fixed module wiring (`FixedModuleManager` 
+ `ModuleWiringBridge` + `GraalVMOAPServerStartUp`)
+- [x] Create a JVM-mode starter with fixed module wiring (`FixedModuleManager` 
+ `GraalVMOAPServerStartUp`)
 - [x] Simplified config file for selected modules (`application.yml`)
 
 ### Phase 2: Build-Time Pre-Compilation & Verification — COMPLETE
@@ -283,11 +290,29 @@ and ~1254 Groovy scripts stored in JARs.
 - [x] Generated class uses Lombok setters, VarHandle, and getter+clear+addAll 
— zero `Field.setAccessible` at runtime
 - [x] Reflective fallback for unknown config types (safety net)
 
+**Config data serialization — COMPLETE:**
+- [x] Precompiler serializes parsed config POJOs to 
`META-INF/config-data/*.json` (7 JSON files)
+- [x] 3 same-FQCN replacement loaders: `MeterConfigs` (meter-analyzer-config), 
`Rules` (otel-rules, envoy-metrics-rules, telegraf-rules, log-mal-rules), 
`LALConfigs` (lal)
+- [x] Replacement loaders deserialize from JSON instead of filesystem YAML, 
with glob matching for enabled rules
+
+**Module system — COMPLETE:**
+- [x] `library-module-for-graalvm`: `ModuleDefine` replacement with direct 
`prepare()` overload (bypasses ServiceLoader)
+- [x] `FixedModuleManager` simplified: calls `module.prepare(manager, 
provider, config, params)` directly
+- [x] `GraalVMOAPServerStartUp`: `configuration.has()` guards for 6 optional 
modules (receiver-zabbix, receiver-zipkin, kafka-fetcher, cilium-fetcher, 
query-zipkin, exporter)
+
 **Distro resource packaging — COMPLETE:**
 - [x] Identified all 236 upstream resource files: 146 runtime files → distro 
`config/`, 89 pre-compiled files → JARs
 - [x] Assembly descriptor (`distribution.xml`) packages runtime config files 
from upstream
 - [x] Pre-compiled OAL/MAL/LAL files excluded from distro (not needed at 
runtime)
 
+**JVM boot verification — COMPLETE:**
+- [x] Full boot with BanyanDB storage: 38 modules started (6 optional modules 
disabled by default)
+- [x] Pre-compiled assets loaded: 620 OAL metrics + 45 dispatchers, 1250 MAL 
scripts, 29 filter scripts, 7 LAL scripts
+- [x] Config data loaded from JSON: 9 meter configs, 55 otel rules, 2 envoy 
rules, 1 telegraf rule, 1 log-mal rule, 8 LAL configs
+- [x] HTTP endpoints: gRPC :11800, HTTP :12800, Firehose :12801, PromQL :9090, 
LogQL :3100, Prometheus :1234
+- [x] Debug logging for per-script MAL/LAL/filter loading (`[count/total]: 
metricName`) for e2e verification
+- [x] Dependency versions centralized in root `pom.xml`
+
 ### Phase 3: Native Image Build
 - [ ] `native-image-maven-plugin` configuration in `oap-graalvm-native`
 - [ ] Run tracing agent to capture reflection/resource/JNI metadata
diff --git a/LAL-IMMIGRATION.md b/LAL-IMMIGRATION.md
index 44a4be3..e6c18cc 100644
--- a/LAL-IMMIGRATION.md
+++ b/LAL-IMMIGRATION.md
@@ -148,12 +148,29 @@ Each test runs both paths and asserts identical `Binding` 
state:
 
 ---
 
+## Config Data Serialization
+
+At build time, the precompiler serializes parsed LAL config POJOs to a JSON 
manifest at
+`META-INF/config-data/lal.json`. This provides the runtime config data (rule 
names, DSL
+strings, layers) for `LogFilterListener` to create `DSL` instances — without 
requiring
+filesystem access to the original YAML files.
+
+| JSON Manifest | Source Directory | Serialized Type |
+|---|---|---|
+| `lal.json` | `lal/` | `Map<String, LALConfigs>` (filename → configs) |
+
+At runtime, the replacement `LALConfigs.load()` deserializes from this JSON 
file instead
+of reading YAML from the filesystem.
+
+---
+
 ## Same-FQCN Replacements (LAL)
 
 | Upstream Class | Upstream Location | Replacement Location | What Changed |
 |---|---|---|---|
 | `DSL` (LAL) | `analyzer/log-analyzer/.../dsl/DSL.java` | 
`oap-libs-for-graalvm/log-analyzer-for-graalvm/` | Complete rewrite. Loads 
pre-compiled `@CompileStatic` Groovy script classes from 
`META-INF/lal-scripts-by-hash.txt` manifest (keyed by SHA-256 hash) instead of 
`GroovyShell.parse()` runtime compilation. |
 | `LogAnalyzerModuleConfig` | 
`analyzer/log-analyzer/.../provider/LogAnalyzerModuleConfig.java` | 
`oap-libs-for-graalvm/log-analyzer-for-graalvm/` | Added `@Setter` at class 
level. Enables reflection-free config loading via Lombok setters. |
+| `LALConfigs` | `analyzer/log-analyzer/.../provider/LALConfigs.java` | 
`oap-libs-for-graalvm/log-analyzer-for-graalvm/` | Complete rewrite of static 
`load()` method. Loads pre-compiled LAL config data from 
`META-INF/config-data/{path}.json` instead of filesystem YAML files via 
`ResourceUtils.getPathFiles()`. |
 
 All replacements are repackaged into `log-analyzer-for-graalvm` via 
`maven-shade-plugin` — the original `.class` files are excluded from the shaded 
JAR.
 
diff --git a/MAL-IMMIGRATION.md b/MAL-IMMIGRATION.md
index 7a53e94..499df5a 100644
--- a/MAL-IMMIGRATION.md
+++ b/MAL-IMMIGRATION.md
@@ -358,6 +358,28 @@ LAL already uses `@CompileStatic` with 
`LALPrecompiledExtension` for type checki
 
 ---
 
+## Config Data Serialization
+
+At build time, the precompiler serializes parsed config POJOs to JSON 
manifests in
+`META-INF/config-data/`. This provides the runtime "wiring" data (metric 
prefixes,
+rule names, expression lookup keys) that connects pre-compiled Groovy scripts 
to
+incoming metrics — without requiring filesystem access to the original YAML 
files.
+
+| JSON Manifest | Source Directory | Serialized Type |
+|---|---|---|
+| `meter-analyzer-config.json` | `meter-analyzer-config/` | `Map<String, 
MeterConfig>` (filename → config) |
+| `otel-rules.json` | `otel-rules/` | `List<Rule>` |
+| `envoy-metrics-rules.json` | `envoy-metrics-rules/` | `List<Rule>` |
+| `log-mal-rules.json` | `log-mal-rules/` | `List<Rule>` |
+| `telegraf-rules.json` | `telegraf-rules/` | `List<Rule>` |
+| `zabbix-rules.json` | `zabbix-rules/` | `List<Rule>` |
+
+At runtime, replacement loader classes (`MeterConfigs`, `Rules`) deserialize 
from
+these JSON files instead of reading YAML from the filesystem. Each logs that 
configs
+are loaded from the pre-compiled distro.
+
+---
+
 ## Same-FQCN Replacements (MAL)
 
 | Upstream Class | Upstream Location | Replacement Location | What Changed |
@@ -365,6 +387,8 @@ LAL already uses `@CompileStatic` with 
`LALPrecompiledExtension` for type checki
 | `MeterSystem` | `server-core/.../analysis/meter/MeterSystem.java` | 
`oap-libs-for-graalvm/server-core-for-graalvm/` | Complete rewrite. Reads 
`@MeterFunction` classes from `META-INF/annotation-scan/MeterFunction.txt` 
manifest instead of Guava `ClassPath.from()`. Loads pre-generated Javassist 
meter classes from classpath instead of runtime `ClassPool.makeClass()`. |
 | `DSL` (MAL) | `analyzer/meter-analyzer/.../dsl/DSL.java` | 
`oap-libs-for-graalvm/meter-analyzer-for-graalvm/` | Complete rewrite. Loads 
pre-compiled Groovy `DelegatingScript` classes from 
`META-INF/mal-groovy-scripts.txt` manifest instead of `GroovyShell.parse()` 
runtime compilation. |
 | `FilterExpression` | `analyzer/meter-analyzer/.../dsl/FilterExpression.java` 
| `oap-libs-for-graalvm/meter-analyzer-for-graalvm/` | Complete rewrite. Loads 
pre-compiled Groovy filter closure classes from 
`META-INF/mal-filter-scripts.properties` manifest instead of 
`GroovyShell.evaluate()` runtime compilation. |
+| `Rules` | `analyzer/meter-analyzer/.../prometheus/rule/Rules.java` | 
`oap-libs-for-graalvm/meter-analyzer-for-graalvm/` | Complete rewrite. Loads 
pre-compiled rule data from `META-INF/config-data/{path}.json` instead of 
filesystem YAML files via `ResourceUtils.getPath()` + `Files.walk()`. |
+| `MeterConfigs` | 
`analyzer/agent-analyzer/.../meter/config/MeterConfigs.java` | 
`oap-libs-for-graalvm/agent-analyzer-for-graalvm/` | Complete rewrite. Loads 
pre-compiled meter config data from `META-INF/config-data/{path}.json` instead 
of filesystem YAML files via `ResourceUtils.getPathFiles()`. |
 
 All replacements are repackaged into their respective `-for-graalvm` modules 
via `maven-shade-plugin` — the original `.class` files are excluded from the 
shaded JARs.
 
diff --git a/Makefile b/Makefile
index 68f3530..27430d3 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ SW_VERSION := $(shell grep '<revision>' skywalking/pom.xml | 
head -1 | sed 's/.*
 MVN := ./mvnw
 MVN_ARGS := -Dskywalking.version=$(SW_VERSION)
 
-.PHONY: all clean build init-submodules build-skywalking build-distro compile 
test javadoc dist info
+.PHONY: all clean build init-submodules build-skywalking build-distro compile 
test javadoc dist info docker-up docker-down boot shutdown
 
 all: build
 
@@ -69,3 +69,24 @@ build: build-skywalking build-distro
 clean:
        $(MVN) clean $(MVN_ARGS)
        cd skywalking && ../mvnw clean
+
+# Start BanyanDB for local development
+docker-up:
+       docker compose -f docker/docker-compose.yml up -d
+       @echo "Waiting for BanyanDB to be ready..."
+       @until docker compose -f docker/docker-compose.yml exec banyandb sh -c 
'nc -nz 127.0.0.1 17912' 2>/dev/null; do sleep 1; done
+       @echo "BanyanDB is ready on localhost:17912"
+
+# Stop BanyanDB
+docker-down:
+       docker compose -f docker/docker-compose.yml down
+
+# Stop a previously running OAP server
+shutdown:
+       
@oap-graalvm-server/target/oap-graalvm-jvm-distro/oap-graalvm-jvm-distro/bin/oapServiceStop.sh
 2>/dev/null || true
+
+# Build distro and boot OAP with BanyanDB
+boot: build-distro docker-up
+       SW_STORAGE_BANYANDB_TARGETS=localhost:17912 \
+       SW_CLUSTER=standalone \
+         
oap-graalvm-server/target/oap-graalvm-jvm-distro/oap-graalvm-jvm-distro/bin/oapService.sh
diff --git a/build-tools/precompiler/pom.xml b/build-tools/precompiler/pom.xml
index 2bbe6ad..d912eb8 100644
--- a/build-tools/precompiler/pom.xml
+++ b/build-tools/precompiler/pom.xml
@@ -84,6 +84,18 @@
             <artifactId>cilium-fetcher-plugin</artifactId>
         </dependency>
 
+        <!-- Agent analyzer (for MeterConfig POJO used in config 
serialization) -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>agent-analyzer</artifactId>
+        </dependency>
+
+        <!-- Jackson for config data JSON serialization -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
         <!-- Lombok -->
         <dependency>
             <groupId>org.projectlombok</groupId>
diff --git 
a/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
 
b/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
index c1ba98f..db3b0d2 100644
--- 
a/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
+++ 
b/build-tools/precompiler/src/main/java/org/apache/skywalking/oap/server/buildtools/precompiler/Precompiler.java
@@ -17,12 +17,16 @@
 
 package org.apache.skywalking.oap.server.buildtools.precompiler;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.ClassPath;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -32,6 +36,7 @@ import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -42,6 +47,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.meter.analyzer.MetricConvert;
 import org.apache.skywalking.oap.log.analyzer.provider.LALConfig;
 import org.apache.skywalking.oap.log.analyzer.provider.LALConfigs;
+import 
org.apache.skywalking.oap.server.analyzer.provider.meter.config.MeterConfig;
 import org.apache.skywalking.oap.meter.analyzer.dsl.DSL;
 import org.apache.skywalking.oap.meter.analyzer.dsl.FilterExpression;
 import org.apache.skywalking.oap.meter.analyzer.prometheus.rule.MetricsRule;
@@ -229,27 +235,40 @@ public class Precompiler {
 
         MeterSystem meterSystem = new MeterSystem(null);
         int totalRules = 0;
+        Map<String, List<Rule>> rulesByPath = new LinkedHashMap<>();
 
         // 1. Agent meter configs (meter-analyzer-config/*.yaml)
-        totalRules += loadAndCompileRules("meter-analyzer-config", 
List.of("*"), meterSystem);
+        List<Rule> meterAnalyzerRules = 
loadAndCompileRules("meter-analyzer-config", List.of("*"), meterSystem);
+        totalRules += meterAnalyzerRules.size();
+        rulesByPath.put("meter-analyzer-config", meterAnalyzerRules);
 
         // 2. OTel rules (otel-rules/*.yaml + otel-rules/**/*.yaml) — includes 
root-level files
-        totalRules += loadAndCompileRules("otel-rules", List.of("*", "**/*"), 
meterSystem);
+        List<Rule> otelRules = loadAndCompileRules("otel-rules", List.of("*", 
"**/*"), meterSystem);
+        totalRules += otelRules.size();
+        rulesByPath.put("otel-rules", otelRules);
 
         // 3. Log MAL rules (log-mal-rules/*.yaml)
-        totalRules += loadAndCompileRules("log-mal-rules", List.of("*"), 
meterSystem);
+        List<Rule> logMalRules = loadAndCompileRules("log-mal-rules", 
List.of("*"), meterSystem);
+        totalRules += logMalRules.size();
+        rulesByPath.put("log-mal-rules", logMalRules);
 
         // 4. Envoy metrics rules (envoy-metrics-rules/*.yaml)
-        totalRules += loadAndCompileRules("envoy-metrics-rules", List.of("*"), 
meterSystem);
+        List<Rule> envoyRules = loadAndCompileRules("envoy-metrics-rules", 
List.of("*"), meterSystem);
+        totalRules += envoyRules.size();
+        rulesByPath.put("envoy-metrics-rules", envoyRules);
 
         // 5. Telegraf rules (telegraf-rules/*.yaml)
         // Shares metricPrefix=meter_vm with otel-rules/vm.yaml — combination 
pattern:
         // multiple expressions from different sources aggregate into the same 
metrics.
-        totalRules += loadAndCompileRules("telegraf-rules", List.of("*"), 
meterSystem);
+        List<Rule> telegrafRules = loadAndCompileRules("telegraf-rules", 
List.of("*"), meterSystem);
+        totalRules += telegrafRules.size();
+        rulesByPath.put("telegraf-rules", telegrafRules);
 
         // 6. Zabbix rules (zabbix-rules/*.yaml)
         // Uses 'metrics' field instead of 'metricsRules', requires custom 
loading.
-        totalRules += loadAndCompileZabbixRules("zabbix-rules", meterSystem);
+        List<Rule> zabbixRules = loadAndCompileZabbixRules("zabbix-rules", 
meterSystem);
+        totalRules += zabbixRules.size();
+        rulesByPath.put("zabbix-rules", zabbixRules);
 
         // Write manifests
         Path metaInf = Path.of(outputDir, "META-INF");
@@ -279,17 +298,22 @@ public class Precompiler {
             meterSystem.getExportedClasses().size(),
             DSL.getScriptRegistry().size(),
             FilterExpression.getScriptRegistry().size());
+
+        // ---- Serialize config data as JSON for runtime loaders ----
+        serializeMALConfigData(outputDir, rulesByPath);
     }
 
     /**
      * Load rules from a resource directory and compile them through the MAL 
pipeline.
+     * Returns the loaded rules for config data serialization.
      */
-    private static int loadAndCompileRules(String path, List<String> 
enabledPatterns,
-                                           MeterSystem meterSystem) {
+    private static List<Rule> loadAndCompileRules(String path, List<String> 
enabledPatterns,
+                                                  MeterSystem meterSystem) {
+        List<Rule> loadedRules = Collections.emptyList();
         int count = 0;
         try {
-            List<Rule> rules = Rules.loadRules(path, enabledPatterns);
-            for (Rule rule : rules) {
+            loadedRules = Rules.loadRules(path, enabledPatterns);
+            for (Rule rule : loadedRules) {
                 try {
                     new MetricConvert(rule, meterSystem);
                     count++;
@@ -302,16 +326,18 @@ public class Precompiler {
         } catch (Exception e) {
             log.warn("Failed to load rules from {}", path, e);
         }
-        return count;
+        return loadedRules;
     }
 
     /**
      * Load Zabbix rules which use 'metrics' field instead of 'metricsRules'.
      * Parses the YAML manually and maps into a Rule for MetricConvert.
+     * Returns the loaded rules for config data serialization.
      */
     @SuppressWarnings("unchecked")
-    private static int loadAndCompileZabbixRules(String path,
-                                                 MeterSystem meterSystem) {
+    private static List<Rule> loadAndCompileZabbixRules(String path,
+                                                        MeterSystem 
meterSystem) {
+        List<Rule> loadedRules = new ArrayList<>();
         int count = 0;
         try {
             File[] files = ResourceUtils.getPathFiles(path);
@@ -350,6 +376,7 @@ public class Precompiler {
                     }
 
                     new MetricConvert(rule, meterSystem);
+                    loadedRules.add(rule);
                     count++;
                 } catch (Exception e) {
                     log.warn("Failed to compile Zabbix rule: {}", 
resourcePath, e);
@@ -359,7 +386,7 @@ public class Precompiler {
         } catch (Exception e) {
             log.warn("Failed to load rules from {}", path, e);
         }
-        return count;
+        return loadedRules;
     }
 
     /**
@@ -374,10 +401,13 @@ public class Precompiler {
         // Enumerate all LAL YAML files from classpath
         File[] lalFiles = ResourceUtils.getPathFiles("lal");
         List<String> lalFileNames = new ArrayList<>();
+        Map<String, File> lalFileMap = new LinkedHashMap<>();
         for (File f : lalFiles) {
             String name = f.getName();
             if (name.endsWith(".yaml") || name.endsWith(".yml")) {
-                lalFileNames.add(name.substring(0, name.lastIndexOf('.')));
+                String key = name.substring(0, name.lastIndexOf('.'));
+                lalFileNames.add(key);
+                lalFileMap.put(key, f);
             }
         }
 
@@ -420,6 +450,9 @@ public class Precompiler {
         log.info("LAL pre-compilation: {} rules, {} scripts",
             totalRules,
             
org.apache.skywalking.oap.log.analyzer.dsl.DSL.getScriptRegistry().size());
+
+        // ---- Serialize LAL config data as JSON for runtime loader ----
+        serializeLALConfigData(outputDir, lalFileMap);
     }
 
     /**
@@ -560,6 +593,88 @@ public class Precompiler {
         return result;
     }
 
+    /**
+     * Serialize MAL config data (Rules and MeterConfigs) as JSON for runtime 
loaders.
+     * At runtime, replacement loader classes deserialize from these JSON 
files instead
+     * of reading YAML from the filesystem.
+     */
+    private static void serializeMALConfigData(String outputDir,
+                                               Map<String, List<Rule>> 
rulesByPath) throws Exception {
+        ObjectMapper mapper = new 
ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
+        Path configDataDir = Path.of(outputDir, "META-INF", "config-data");
+        Files.createDirectories(configDataDir);
+
+        // Serialize MeterConfig objects for meter-analyzer-config (runtime 
uses MeterConfigs.loadConfig)
+        List<Rule> meterAnalyzerRules = 
rulesByPath.get("meter-analyzer-config");
+        if (meterAnalyzerRules != null) {
+            Map<String, MeterConfig> meterConfigs = 
loadMeterConfigs("meter-analyzer-config");
+            
mapper.writeValue(configDataDir.resolve("meter-analyzer-config.json").toFile(), 
meterConfigs);
+            log.info("Serialized {} MeterConfig entries from 
meter-analyzer-config to config-data JSON",
+                meterConfigs.size());
+        }
+
+        // Serialize Rule lists for each path (runtime uses Rules.loadRules)
+        for (Map.Entry<String, List<Rule>> entry : rulesByPath.entrySet()) {
+            String path = entry.getKey();
+            if ("meter-analyzer-config".equals(path)) {
+                // meter-analyzer-config is already serialized as MeterConfig 
above
+                continue;
+            }
+            List<Rule> rules = entry.getValue();
+            mapper.writeValue(configDataDir.resolve(path + ".json").toFile(), 
rules);
+            log.info("Serialized {} Rule entries from {} to config-data JSON", 
rules.size(), path);
+        }
+    }
+
+    /**
+     * Load MeterConfig objects from meter-analyzer-config YAML files.
+     * Returns a Map keyed by filename (without extension) for filtering at 
runtime.
+     */
+    private static Map<String, MeterConfig> loadMeterConfigs(String path) 
throws Exception {
+        File[] files = ResourceUtils.getPathFiles(path);
+        Map<String, MeterConfig> result = new LinkedHashMap<>();
+        Yaml yaml = new Yaml();
+        for (File file : files) {
+            String name = file.getName();
+            if (!name.endsWith(".yaml") && !name.endsWith(".yml")) {
+                continue;
+            }
+            String key = name.substring(0, name.lastIndexOf('.'));
+            try (Reader r = new FileReader(file)) {
+                MeterConfig config = yaml.loadAs(r, MeterConfig.class);
+                if (config != null) {
+                    result.put(key, config);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Serialize LAL config data as JSON for runtime loader.
+     * At runtime, the replacement LALConfigs.load() deserializes from this 
JSON file.
+     */
+    private static void serializeLALConfigData(String outputDir,
+                                               Map<String, File> lalFileMap) 
throws Exception {
+        ObjectMapper mapper = new 
ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
+        Path configDataDir = Path.of(outputDir, "META-INF", "config-data");
+        Files.createDirectories(configDataDir);
+
+        Map<String, LALConfigs> lalConfigMap = new LinkedHashMap<>();
+        Yaml yaml = new Yaml();
+        for (Map.Entry<String, File> entry : lalFileMap.entrySet()) {
+            try (Reader r = new FileReader(entry.getValue())) {
+                LALConfigs config = yaml.loadAs(r, LALConfigs.class);
+                if (config != null) {
+                    lalConfigMap.put(entry.getKey(), config);
+                }
+            }
+        }
+
+        mapper.writeValue(configDataDir.resolve("lal.json").toFile(), 
lalConfigMap);
+        log.info("Serialized {} LALConfigs entries from lal to config-data 
JSON", lalConfigMap.size());
+    }
+
     private static void writeManifest(Path path, List<String> lines) throws 
IOException {
         Files.write(path, lines, StandardCharsets.UTF_8);
     }
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
new file mode 100644
index 0000000..1774dc0
--- /dev/null
+++ b/docker/docker-compose.yml
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+services:
+  banyandb:
+    image: 
"ghcr.io/apache/skywalking-banyandb:${SW_BANYANDB_COMMIT:-74334e027b7fad414c9773f803163b5c97a9655b}"
+    ports:
+      - "17912:17912"
+      - "17913:17913"
+    command: standalone --stream-root-path /tmp/stream-data 
--measure-root-path /tmp/measure-data --property-root-path /tmp/property-data 
--trace-root-path /tmp/trace-data
+    healthcheck:
+      test: [ "CMD", "sh", "-c", "nc -nz 127.0.0.1 17912" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
diff --git a/oap-graalvm-server/pom.xml b/oap-graalvm-server/pom.xml
index 2718684..56888aa 100644
--- a/oap-graalvm-server/pom.xml
+++ b/oap-graalvm-server/pom.xml
@@ -39,6 +39,12 @@
     -->
     <dependencyManagement>
         <dependencies>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-module</artifactId>
+                <version>${skywalking.version}</version>
+                <scope>provided</scope>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>server-core</artifactId>
@@ -116,6 +122,10 @@
 
     <dependencies>
         <!-- Repackaged OAP libs with GraalVM-compatible replacements baked in 
-->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-module-for-graalvm</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
             <artifactId>server-core-for-graalvm</artifactId>
@@ -166,6 +176,10 @@
         </dependency>
 
         <!-- Core (non-repackaged) -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>receiver-proto</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
             <artifactId>oal-rt</artifactId>
@@ -253,6 +267,11 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>skywalking-async-profiler-receiver-plugin</artifactId>
         </dependency>
+        <!-- Upstream marks this as 'provided'; we need it at runtime for 
JFREventType -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>library-async-profiler-jfr-parser</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
             <artifactId>skywalking-pprof-receiver-plugin</artifactId>
@@ -335,6 +354,23 @@
             <classifier>generated</classifier>
         </dependency>
 
+        <!--
+          Transitive deps that are excluded by provided-scope overrides above
+          but are needed at runtime.
+        -->
+        <dependency>
+            <groupId>org.apache.groovy</groupId>
+            <artifactId>groovy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
         <!-- Lombok -->
         <dependency>
             <groupId>org.projectlombok</groupId>
@@ -350,19 +386,16 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>5.11.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-junit-jupiter</artifactId>
-            <version>5.11.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.powermock</groupId>
             <artifactId>powermock-reflect</artifactId>
-            <version>2.0.9</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
index 4771254..a510237 100644
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/graalvm/GraalVMOAPServerStartUp.java
@@ -200,12 +200,16 @@ public class GraalVMOAPServerStartUp {
         manager.register(new ProfileModule(), new ProfileModuleProvider());
         manager.register(new AsyncProfilerModule(), new 
AsyncProfilerModuleProvider());
         manager.register(new PprofModule(), new PprofModuleProvider());
-        manager.register(new ZabbixReceiverModule(), new 
ZabbixReceiverProvider());
+        if (configuration.has("receiver-zabbix")) {
+            manager.register(new ZabbixReceiverModule(), new 
ZabbixReceiverProvider());
+        }
         manager.register(new MeshReceiverModule(), new MeshReceiverProvider());
         manager.register(new EnvoyMetricReceiverModule(), new 
EnvoyMetricReceiverProvider());
         manager.register(new MeterReceiverModule(), new 
MeterReceiverProvider());
         manager.register(new OtelMetricReceiverModule(), new 
OtelMetricReceiverProvider());
-        manager.register(new ZipkinReceiverModule(), new 
ZipkinReceiverProvider());
+        if (configuration.has("receiver-zipkin")) {
+            manager.register(new ZipkinReceiverModule(), new 
ZipkinReceiverProvider());
+        }
         manager.register(new BrowserModule(), new BrowserModuleProvider());
         manager.register(new LogModule(), new LogModuleProvider());
         manager.register(new EventModule(), new EventModuleProvider());
@@ -214,13 +218,19 @@ public class GraalVMOAPServerStartUp {
         manager.register(new AWSFirehoseReceiverModule(), new 
AWSFirehoseReceiverModuleProvider());
         manager.register(new ConfigurationDiscoveryModule(), new 
ConfigurationDiscoveryProvider());
 
-        // Fetchers
-        manager.register(new KafkaFetcherModule(), new KafkaFetcherProvider());
-        manager.register(new CiliumFetcherModule(), new 
CiliumFetcherProvider());
+        // Fetchers (optional, disabled by default with selector: -)
+        if (configuration.has("kafka-fetcher")) {
+            manager.register(new KafkaFetcherModule(), new 
KafkaFetcherProvider());
+        }
+        if (configuration.has("cilium-fetcher")) {
+            manager.register(new CiliumFetcherModule(), new 
CiliumFetcherProvider());
+        }
 
         // Query
         manager.register(new QueryModule(), new GraphQLQueryProvider());
-        manager.register(new ZipkinQueryModule(), new ZipkinQueryProvider());
+        if (configuration.has("query-zipkin")) {
+            manager.register(new ZipkinQueryModule(), new 
ZipkinQueryProvider());
+        }
         manager.register(new PromQLModule(), new PromQLProvider());
         manager.register(new LogQLModule(), new LogQLProvider());
         manager.register(new StatusQueryModule(), new StatusQueryProvider());
@@ -228,8 +238,10 @@ public class GraalVMOAPServerStartUp {
         // Alarm
         manager.register(new AlarmModule(), new AlarmModuleProvider());
 
-        // Exporter
-        manager.register(new ExporterModule(), new ExporterProvider());
+        // Exporter (optional, disabled by default with selector: -)
+        if (configuration.has("exporter")) {
+            manager.register(new ExporterModule(), new ExporterProvider());
+        }
 
         // Health Checker
         manager.register(new HealthCheckerModule(), new 
HealthCheckerProvider());
diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/FixedModuleManager.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/FixedModuleManager.java
index a4915d9..c4afde3 100644
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/FixedModuleManager.java
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/FixedModuleManager.java
@@ -17,17 +17,20 @@
 
 package org.apache.skywalking.oap.server.library.module;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
  * A ModuleManager that uses fixed module wiring instead of ServiceLoader 
discovery.
  * Modules and providers are explicitly registered before initialization.
+ * Uses the direct-wiring prepare() overload added in the 
library-module-for-graalvm
+ * replacement of ModuleDefine.
  */
 public class FixedModuleManager extends ModuleManager {
 
-    private final Map<String, ModuleWiringBridge.ModuleBinding> bindings = new 
LinkedHashMap<>();
-    private final Map<String, ModuleDefine> loadedModules = new 
LinkedHashMap<>();
+    private final List<ModuleBinding> bindings = new ArrayList<>();
 
     public FixedModuleManager(String description) {
         super(description);
@@ -35,36 +38,56 @@ public class FixedModuleManager extends ModuleManager {
 
     /**
      * Register a module with its chosen provider.
-     * The module name is derived from {@link ModuleDefine#name()}.
      */
     public void register(ModuleDefine moduleDefine, ModuleProvider provider) {
-        bindings.put(moduleDefine.name(), new 
ModuleWiringBridge.ModuleBinding(moduleDefine, provider));
+        bindings.add(new ModuleBinding(moduleDefine, provider));
     }
 
     /**
      * Initialize all registered modules using fixed wiring (no ServiceLoader).
+     * Calls the direct-wiring prepare() overload on ModuleDefine, then uses
+     * BootstrapFlow for dependency-ordered start and notify.
      */
     public void initFixed(ApplicationConfiguration configuration)
         throws ModuleNotFoundException, ProviderNotFoundException, 
ServiceNotProvidedException,
         CycleDependencyException, ModuleConfigException, ModuleStartException {
-        ModuleWiringBridge.initAll(this, bindings, configuration);
-        // Populate our loaded modules map for find()/has() lookups
-        for (Map.Entry<String, ModuleWiringBridge.ModuleBinding> entry : 
bindings.entrySet()) {
-            loadedModules.put(entry.getKey(), entry.getValue().moduleDefine());
+
+        Map<String, ModuleDefine> loadedModules = new LinkedHashMap<>();
+        TerminalFriendlyTable bootingParameters = getBootingParameters();
+
+        // Phase 1: Prepare all modules using direct provider wiring
+        for (ModuleBinding binding : bindings) {
+            String moduleName = binding.moduleDefine.name();
+            binding.moduleDefine.prepare(
+                this,
+                binding.provider,
+                configuration.getModuleConfiguration(moduleName),
+                bootingParameters
+            );
+            loadedModules.put(moduleName, binding.moduleDefine);
         }
+
+        // Phase 2: Start and notify (using BootstrapFlow for dependency 
ordering)
+        BootstrapFlow bootstrapFlow = new BootstrapFlow(loadedModules);
+        bootstrapFlow.start(this);
+        bootstrapFlow.notifyAfterCompleted();
     }
 
     @Override
     public boolean has(String moduleName) {
-        return loadedModules.containsKey(moduleName);
+        return bindings.stream().anyMatch(b -> 
b.moduleDefine.name().equals(moduleName));
     }
 
     @Override
     public ModuleProviderHolder find(String moduleName) throws 
ModuleNotFoundRuntimeException {
-        ModuleDefine module = loadedModules.get(moduleName);
-        if (module != null) {
-            return module;
+        for (ModuleBinding binding : bindings) {
+            if (binding.moduleDefine.name().equals(moduleName)) {
+                return binding.moduleDefine;
+            }
         }
         throw new ModuleNotFoundRuntimeException(moduleName + " missing.");
     }
+
+    private record ModuleBinding(ModuleDefine moduleDefine, ModuleProvider 
provider) {
+    }
 }
diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleWiringBridge.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleWiringBridge.java
deleted file mode 100644
index f0ddb28..0000000
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleWiringBridge.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.skywalking.oap.server.library.module;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import lombok.extern.slf4j.Slf4j;
-
-import static 
org.apache.skywalking.oap.server.library.util.YamlConfigLoaderUtils.copyProperties;
-
-/**
- * Bridge class in the same package as ModuleDefine/ModuleProvider to access
- * package-private APIs. Used by the fixed-wiring starter to bypass SPI 
discovery.
- */
-@Slf4j
-public class ModuleWiringBridge {
-
-    /**
-     * Wire a ModuleDefine with a specific ModuleProvider directly, bypassing 
ServiceLoader.
-     * Replicates the logic in {@link ModuleDefine#prepare} but with a 
pre-selected provider.
-     */
-    public static void wireAndPrepare(ModuleManager moduleManager,
-                                      ModuleDefine module,
-                                      ModuleProvider provider,
-                                      
ApplicationConfiguration.ModuleConfiguration configuration,
-                                      TerminalFriendlyTable bootingParameters)
-        throws ModuleConfigException, ModuleStartException, 
ServiceNotProvidedException {
-
-        // Wire provider to module (package-private setters)
-        provider.setManager(moduleManager);
-        provider.setModuleDefine(module);
-        provider.setBootingParameters(bootingParameters);
-
-        log.info("Prepare the {} provider in {} module.", provider.name(), 
module.name());
-
-        // Initialize config
-        try {
-            final ModuleProvider.ConfigCreator creator = 
provider.newConfigCreator();
-            if (creator != null) {
-                final Class typeOfConfig = creator.type();
-                if (typeOfConfig != null) {
-                    final ModuleConfig config = (ModuleConfig) 
typeOfConfig.getDeclaredConstructor().newInstance();
-                    copyProperties(
-                        config,
-                        
configuration.getProviderConfiguration(provider.name()),
-                        module.name(),
-                        provider.name()
-                    );
-                    creator.onInitialized(config);
-                }
-            }
-        } catch (IllegalAccessException | NoSuchMethodException | 
InvocationTargetException |
-                 InstantiationException e) {
-            throw new ModuleConfigException(
-                module.name() + " module config transport to config bean 
failure.", e);
-        }
-
-        // Prepare the provider
-        provider.prepare();
-    }
-
-    /**
-     * Initialize all fixed-wired modules: prepare, start, and notify in 
dependency order.
-     *
-     * @param moduleManager  the module manager
-     * @param moduleBindings ordered map of module name -> (ModuleDefine, 
ModuleProvider) pairs
-     * @param configuration  the application configuration
-     */
-    public static void initAll(ModuleManager moduleManager,
-                               Map<String, ModuleBinding> moduleBindings,
-                               ApplicationConfiguration configuration)
-        throws ModuleNotFoundException, ProviderNotFoundException, 
ServiceNotProvidedException,
-        CycleDependencyException, ModuleConfigException, ModuleStartException {
-
-        Map<String, ModuleDefine> loadedModules = new LinkedHashMap<>();
-        TerminalFriendlyTable bootingParameters = 
moduleManager.getBootingParameters();
-
-        // Phase 1: Prepare all modules
-        for (Map.Entry<String, ModuleBinding> entry : 
moduleBindings.entrySet()) {
-            String moduleName = entry.getKey();
-            ModuleBinding binding = entry.getValue();
-
-            wireAndPrepare(
-                moduleManager,
-                binding.moduleDefine(),
-                binding.provider(),
-                configuration.getModuleConfiguration(moduleName),
-                bootingParameters
-            );
-            loadedModules.put(moduleName, binding.moduleDefine());
-        }
-
-        // Phase 2: Start and notify (using BootstrapFlow for dependency 
ordering)
-        BootstrapFlow bootstrapFlow = new BootstrapFlow(loadedModules);
-        bootstrapFlow.start(moduleManager);
-        bootstrapFlow.notifyAfterCompleted();
-    }
-
-    /**
-     * A binding of a ModuleDefine to its chosen ModuleProvider.
-     */
-    public record ModuleBinding(ModuleDefine moduleDefine, ModuleProvider 
provider) {
-    }
-}
diff --git 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
index 593339c..de85c64 100644
--- 
a/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
+++ 
b/oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java
@@ -237,7 +237,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestMaxThreads((int) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
@@ -270,10 +270,10 @@ public class YamlConfigLoaderUtils {
                     cfg.setTopNReportPeriod((int) value);
                     break;
                 case "l1FlushPeriod":
-                    cfg.setL1FlushPeriod((long) value);
+                    cfg.setL1FlushPeriod(((Number) value).longValue());
                     break;
                 case "storageSessionTimeout":
-                    cfg.setStorageSessionTimeout((long) value);
+                    cfg.setStorageSessionTimeout(((Number) value).longValue());
                     break;
                 case "downsampling":
                     cfg.getDownsampling().clear();
@@ -301,13 +301,13 @@ public class YamlConfigLoaderUtils {
                     cfg.setRemoteTimeout((int) value);
                     break;
                 case "maxSizeOfNetworkAddressAlias":
-                    cfg.setMaxSizeOfNetworkAddressAlias((long) value);
+                    cfg.setMaxSizeOfNetworkAddressAlias(((Number) 
value).longValue());
                     break;
                 case "maxSizeOfProfileTask":
-                    cfg.setMaxSizeOfProfileTask((long) value);
+                    cfg.setMaxSizeOfProfileTask(((Number) value).longValue());
                     break;
                 case "maxSizeOfPprofTask":
-                    cfg.setMaxSizeOfPprofTask((long) value);
+                    cfg.setMaxSizeOfPprofTask(((Number) value).longValue());
                     break;
                 case "maxPageSizeOfQueryProfileSnapshot":
                     cfg.setMaxPageSizeOfQueryProfileSnapshot((int) value);
@@ -379,10 +379,10 @@ public class YamlConfigLoaderUtils {
                     cfg.setEnableHierarchy((boolean) value);
                     break;
                 case "maxHeapMemoryUsagePercent":
-                    cfg.setMaxHeapMemoryUsagePercent((long) value);
+                    cfg.setMaxHeapMemoryUsagePercent(((Number) 
value).longValue());
                     break;
                 case "maxDirectMemoryUsage":
-                    cfg.setMaxDirectMemoryUsage((long) value);
+                    cfg.setMaxDirectMemoryUsage(((Number) value).longValue());
                     break;
                 default:
                     log.warn("{} setting is not supported in {} provider of {} 
module",
@@ -654,7 +654,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestContextPath((String) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
@@ -891,7 +891,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestContextPath((String) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
@@ -1043,7 +1043,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setContextPath((String) value);
                     break;
                 case "idleTimeOut":
-                    cfg.setIdleTimeOut((long) value);
+                    cfg.setIdleTimeOut(((Number) value).longValue());
                     break;
                 case "acceptQueueSize":
                     cfg.setAcceptQueueSize((int) value);
@@ -1260,13 +1260,13 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestContextPath((String) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
                     break;
                 case "lookback":
-                    cfg.setLookback((long) value);
+                    cfg.setLookback(((Number) value).longValue());
                     break;
                 case "namesMaxAge":
                     cfg.setNamesMaxAge((int) value);
@@ -1278,7 +1278,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setUiEnvironment((String) value);
                     break;
                 case "uiDefaultLookback":
-                    cfg.setUiDefaultLookback((long) value);
+                    cfg.setUiDefaultLookback(((Number) value).longValue());
                     break;
                 case "uiSearchEnabled":
                     cfg.setUiSearchEnabled((boolean) value);
@@ -1310,7 +1310,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestContextPath((String) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
@@ -1360,7 +1360,7 @@ public class YamlConfigLoaderUtils {
                     cfg.setRestContextPath((String) value);
                     break;
                 case "restIdleTimeOut":
-                    cfg.setRestIdleTimeOut((long) value);
+                    cfg.setRestIdleTimeOut(((Number) value).longValue());
                     break;
                 case "restAcceptQueueSize":
                     cfg.setRestAcceptQueueSize((int) value);
@@ -1456,7 +1456,7 @@ public class YamlConfigLoaderUtils {
             final Object value = src.get(key);
             switch (key) {
                 case "checkIntervalSeconds":
-                    cfg.setCheckIntervalSeconds((long) value);
+                    cfg.setCheckIntervalSeconds(((Number) value).longValue());
                     break;
                 default:
                     log.warn("{} setting is not supported in {} provider of {} 
module",
diff --git 
a/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ReplacementClassStalenessTest.java
 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ReplacementClassStalenessTest.java
new file mode 100644
index 0000000..d49d15f
--- /dev/null
+++ 
b/oap-graalvm-server/src/test/java/org/apache/skywalking/oap/server/graalvm/ReplacementClassStalenessTest.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.graalvm;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Staleness detector for same-FQCN replacement classes.
+ *
+ * <p>Tracks the SHA-256 of each upstream source file that has a same-FQCN
+ * replacement in this project. If an upstream file changes (e.g. after a
+ * {@code skywalking/} submodule update), this test fails with a clear message
+ * indicating which replacement(s) need review and update.
+ *
+ * <p>SHA-256 hashes are recorded in {@code 
replacement-source-sha256.properties}
+ * (same pattern as {@code precompiled-yaml-sha256.properties}).
+ */
+class ReplacementClassStalenessTest {
+
+    private static final String PROPS_RESOURCE = 
"replacement-source-sha256.properties";
+
+    @Test
+    void allReplacementSourcesMatchRecordedSha256() throws Exception {
+        Properties props = loadProperties();
+        assertTrue(!props.isEmpty(),
+            PROPS_RESOURCE + " is empty or not found");
+
+        // Resolve paths relative to project root (oap-graalvm-server -> 
parent)
+        Path projectRoot = Path.of(System.getProperty("user.dir")).getParent();
+
+        List<String> mismatches = new ArrayList<>();
+        List<String> missing = new ArrayList<>();
+
+        for (String relativePath : props.stringPropertyNames()) {
+            String expectedSha = props.getProperty(relativePath).trim();
+            Path upstreamPath = projectRoot.resolve(relativePath);
+
+            if (!Files.exists(upstreamPath)) {
+                missing.add(relativePath);
+            } else {
+                String actualSha = computeFileSha256(upstreamPath);
+                if (!expectedSha.equals(actualSha)) {
+                    mismatches.add(String.format(
+                        "  %s%n    expected: %s%n    actual:   %s",
+                        relativePath, expectedSha, actualSha));
+                }
+            }
+        }
+
+        StringBuilder msg = new StringBuilder();
+        if (!mismatches.isEmpty()) {
+            msg.append("Upstream source files changed — review and update 
these replacements:\n");
+            for (String m : mismatches) {
+                msg.append(m).append('\n');
+            }
+        }
+        if (!missing.isEmpty()) {
+            msg.append("Upstream source files not found:\n");
+            for (String m : missing) {
+                msg.append("  ").append(m).append('\n');
+            }
+        }
+
+        if (msg.length() > 0) {
+            fail(msg.toString());
+        }
+    }
+
+    private Properties loadProperties() throws IOException {
+        Properties props = new Properties();
+        try (InputStream is = getClass().getClassLoader()
+                .getResourceAsStream(PROPS_RESOURCE)) {
+            if (is != null) {
+                props.load(is);
+            }
+        }
+        return props;
+    }
+
+    private static String computeFileSha256(Path path) {
+        try (InputStream is = Files.newInputStream(path)) {
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+            byte[] buffer = new byte[8192];
+            int read;
+            while ((read = is.read(buffer)) != -1) {
+                digest.update(buffer, 0, read);
+            }
+            byte[] hash = digest.digest();
+            StringBuilder hex = new StringBuilder(hash.length * 2);
+            for (byte b : hash) {
+                hex.append(String.format("%02x", b));
+            }
+            return hex.toString();
+        } catch (IOException | NoSuchAlgorithmException e) {
+            return null;
+        }
+    }
+}
diff --git 
a/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties 
b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
new file mode 100644
index 0000000..77f02a3
--- /dev/null
+++ b/oap-graalvm-server/src/test/resources/replacement-source-sha256.properties
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Replacement class upstream source SHA-256 hashes — staleness detector
+# Tracks upstream Java source files that have same-FQCN replacements in this
+# project. When a file's content changes (e.g. after skywalking/ submodule
+# update), ReplacementClassStalenessTest fails, flagging which replacements
+# need review and update.
+#
+# Format: relative/path/to/upstream/Source.java = sha256hex
+# To update: shasum -a 256 <path>
+
+# Module system replacement (direct provider wiring without ServiceLoader)
+skywalking/oap-server/server-library/library-module/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
 = 89add3015c4265f50a13a9e5800d68aaa43e73f50c1224343712d2744b6e2437
+
+# Config loader replacements (load from JSON manifests instead of filesystem 
YAML)
+skywalking/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
 = 979b1d081a7e0aa1b627a525157d9f024f81a3db289e76284c54dbf508c494b1
+skywalking/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.java
 = 1f300c978e9dca2464379463b40544d8114500b1f87d2df10005c518dd71db99
+skywalking/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.java
 = ecb7ddbc94bd4073e885e76c472dddd171e9b11155402faabb33923b55e38eee
diff --git a/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml
index cddbeda..d1c4dd9 100644
--- a/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml
@@ -36,6 +36,10 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>agent-analyzer</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
@@ -58,6 +62,7 @@
                             
<artifact>org.apache.skywalking:agent-analyzer</artifact>
                             <excludes>
                                 
<exclude>org/apache/skywalking/oap/server/analyzer/provider/AnalyzerModuleConfig.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/agent-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
 
b/oap-libs-for-graalvm/agent-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
new file mode 100644
index 0000000..0138a04
--- /dev/null
+++ 
b/oap-libs-for-graalvm/agent-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/meter/config/MeterConfigs.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.analyzer.provider.meter.config;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+
+/**
+ * GraalVM replacement for upstream MeterConfigs.
+ * Original: 
skywalking/oap-server/analyzer/agent-analyzer/src/main/java/.../meter/config/MeterConfigs.java
+ * Repackaged into agent-analyzer-for-graalvm via maven-shade-plugin (replaces 
original .class in shaded JAR).
+ *
+ * Change: Complete rewrite. Loads pre-compiled meter config data from JSON 
manifests
+ * (META-INF/config-data/{path}.json) instead of filesystem YAML files via 
ResourceUtils.getPathFiles().
+ * Why: The distro intentionally excludes raw YAML config directories 
(meter-analyzer-config, etc.)
+ * — their Groovy expressions are pre-compiled at build time. Config data 
(metric prefixes, rule names)
+ * is serialized as JSON by the precompiler for runtime wiring.
+ */
+@Slf4j
+public class MeterConfigs {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * Load all configs from pre-compiled JSON manifest.
+     */
+    public static List<MeterConfig> loadConfig(String path, List<String> 
fileNames) throws ModuleStartException {
+        if (CollectionUtils.isEmpty(fileNames)) {
+            return Collections.emptyList();
+        }
+
+        log.info("Loading meter configs from pre-compiled distro ({})", path);
+
+        String resourcePath = "META-INF/config-data/" + path + ".json";
+        try (InputStream is = 
MeterConfigs.class.getClassLoader().getResourceAsStream(resourcePath)) {
+            if (is == null) {
+                throw new ModuleStartException(
+                    "Pre-compiled config data not found: " + resourcePath
+                    + ". Ensure the precompiler has been run.");
+            }
+
+            Map<String, MeterConfig> allConfigs = MAPPER.readValue(
+                is, new TypeReference<Map<String, MeterConfig>>() { });
+
+            List<MeterConfig> result = allConfigs.entrySet().stream()
+                .filter(e -> fileNames.contains(e.getKey()))
+                .map(Map.Entry::getValue)
+                .collect(Collectors.toList());
+
+            log.info("Loaded {} pre-compiled meter configs from {} (filtered 
from {} available)",
+                result.size(), path, allConfigs.size());
+            return result;
+        } catch (ModuleStartException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ModuleStartException("Load pre-compiled meter configs 
failed", e);
+        }
+    }
+}
diff --git a/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/library-module-for-graalvm/pom.xml
similarity index 82%
copy from oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml
copy to oap-libs-for-graalvm/library-module-for-graalvm/pom.xml
index cddbeda..9b907fa 100644
--- a/oap-libs-for-graalvm/agent-analyzer-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/library-module-for-graalvm/pom.xml
@@ -27,14 +27,14 @@
         <version>1.0.0-SNAPSHOT</version>
     </parent>
 
-    <artifactId>agent-analyzer-for-graalvm</artifactId>
-    <name>Agent Analyzer for GraalVM</name>
-    <description>Repackaged agent-analyzer with GraalVM-compatible 
config</description>
+    <artifactId>library-module-for-graalvm</artifactId>
+    <name>Library Module for GraalVM</name>
+    <description>Repackaged library-module with ModuleDefine that supports 
direct provider wiring</description>
 
     <dependencies>
         <dependency>
             <groupId>org.apache.skywalking</groupId>
-            <artifactId>agent-analyzer</artifactId>
+            <artifactId>library-module</artifactId>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
@@ -50,14 +50,14 @@
                 <configuration>
                     <artifactSet>
                         <includes>
-                            
<include>org.apache.skywalking:agent-analyzer</include>
+                            
<include>org.apache.skywalking:library-module</include>
                         </includes>
                     </artifactSet>
                     <filters>
                         <filter>
-                            
<artifact>org.apache.skywalking:agent-analyzer</artifact>
+                            
<artifact>org.apache.skywalking:library-module</artifact>
                             <excludes>
-                                
<exclude>org/apache/skywalking/oap/server/analyzer/provider/AnalyzerModuleConfig.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/library/module/ModuleDefine.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/library-module-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
 
b/oap-libs-for-graalvm/library-module-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
new file mode 100644
index 0000000..7c4c049
--- /dev/null
+++ 
b/oap-libs-for-graalvm/library-module-for-graalvm/src/main/java/org/apache/skywalking/oap/server/library/module/ModuleDefine.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.library.module;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ServiceLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static 
org.apache.skywalking.oap.server.library.util.YamlConfigLoaderUtils.copyProperties;
+
+/**
+ * GraalVM replacement for upstream ModuleDefine.
+ * Original: 
skywalking/oap-server/server-library/library-module/src/main/java/.../module/ModuleDefine.java
+ * Repackaged into library-module-for-graalvm via maven-shade-plugin (replaces 
original .class in shaded JAR).
+ *
+ * Change: Added {@link #prepare(ModuleManager, ModuleProvider, 
ApplicationConfiguration.ModuleConfiguration,
+ * TerminalFriendlyTable)} overload that accepts a pre-selected provider 
directly, bypassing ServiceLoader
+ * discovery. This enables fixed module wiring for GraalVM without reflection 
hacks.
+ * Why: The distro uses FixedModuleManager with directly-constructed modules 
and providers.
+ * The upstream prepare() method requires ServiceLoader to find providers, 
which we bypass entirely.
+ */
+public abstract class ModuleDefine implements ModuleProviderHolder {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ModuleDefine.class);
+
+    private ModuleProvider loadedProvider = null;
+
+    private final String name;
+
+    public ModuleDefine(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the module name
+     */
+    public final String name() {
+        return name;
+    }
+
+    /**
+     * @return the {@link Service} provided by this module.
+     */
+    public abstract Class[] services();
+
+    /**
+     * Run the prepare stage for the module, including finding all potential 
providers, and asking them to prepare.
+     *
+     * @param moduleManager of this module
+     * @param configuration of this module
+     * @throws ProviderNotFoundException when even don't find a single one 
providers.
+     */
+    void prepare(ModuleManager moduleManager,
+                 ApplicationConfiguration.ModuleConfiguration configuration,
+                 ServiceLoader<ModuleProvider> moduleProviderLoader,
+                 TerminalFriendlyTable bootingParameters)
+        throws ProviderNotFoundException, ServiceNotProvidedException, 
ModuleConfigException, ModuleStartException {
+        for (ModuleProvider provider : moduleProviderLoader) {
+            if (!configuration.has(provider.name())) {
+                continue;
+            }
+
+            if (provider.module().equals(getClass())) {
+                if (loadedProvider == null) {
+                    loadedProvider = provider;
+                    loadedProvider.setManager(moduleManager);
+                    loadedProvider.setModuleDefine(this);
+                    loadedProvider.setBootingParameters(bootingParameters);
+                } else {
+                    throw new DuplicateProviderException(
+                        this.name() + " module has one " + 
loadedProvider.name() + "[" + loadedProvider
+                            .getClass()
+                            .getName() + "] provider already, " + 
provider.name() + "[" + provider.getClass()
+                                                                               
                   .getName() + "] is defined as 2nd provider.");
+                }
+            }
+
+        }
+
+        if (loadedProvider == null) {
+            throw new ProviderNotFoundException(this.name() + " module no 
provider found.");
+        }
+
+        LOGGER.info("Prepare the {} provider in {} module.", 
loadedProvider.name(), this.name());
+        try {
+            final ModuleProvider.ConfigCreator creator = 
loadedProvider.newConfigCreator();
+            if (creator != null) {
+                final Class typeOfConfig = creator.type();
+                if (typeOfConfig != null) {
+                    final ModuleConfig config = (ModuleConfig) 
typeOfConfig.getDeclaredConstructor().newInstance();
+                    copyProperties(
+                        config,
+                        
configuration.getProviderConfiguration(loadedProvider.name()), this.name(),
+                        loadedProvider.name()
+                    );
+                    creator.onInitialized(config);
+                }
+            }
+        } catch (IllegalAccessException | NoSuchMethodException | 
InvocationTargetException |
+                 InstantiationException e) {
+            throw new ModuleConfigException(this.name() + " module config 
transport to config bean failure.", e);
+        }
+        loadedProvider.prepare();
+    }
+
+    /**
+     * Prepare with a pre-selected provider, bypassing ServiceLoader discovery.
+     * Used by FixedModuleManager for direct module wiring.
+     */
+    void prepare(ModuleManager moduleManager,
+                 ModuleProvider provider,
+                 ApplicationConfiguration.ModuleConfiguration configuration,
+                 TerminalFriendlyTable bootingParameters)
+        throws ModuleConfigException, ModuleStartException {
+
+        loadedProvider = provider;
+        loadedProvider.setManager(moduleManager);
+        loadedProvider.setModuleDefine(this);
+        loadedProvider.setBootingParameters(bootingParameters);
+
+        LOGGER.info("Prepare the {} provider in {} module.", 
loadedProvider.name(), this.name());
+        try {
+            final ModuleProvider.ConfigCreator creator = 
loadedProvider.newConfigCreator();
+            if (creator != null) {
+                final Class typeOfConfig = creator.type();
+                if (typeOfConfig != null) {
+                    final ModuleConfig config = (ModuleConfig) 
typeOfConfig.getDeclaredConstructor().newInstance();
+                    copyProperties(
+                        config,
+                        
configuration.getProviderConfiguration(loadedProvider.name()), this.name(),
+                        loadedProvider.name()
+                    );
+                    creator.onInitialized(config);
+                }
+            }
+        } catch (IllegalAccessException | NoSuchMethodException | 
InvocationTargetException |
+                 InstantiationException e) {
+            throw new ModuleConfigException(this.name() + " module config 
transport to config bean failure.", e);
+        }
+        loadedProvider.prepare();
+    }
+
+    @Override
+    public final ModuleProvider provider() throws DuplicateProviderException, 
ProviderNotFoundException {
+        if (loadedProvider == null) {
+            throw new ProviderNotFoundException("There is no module provider 
in " + this.name() + " module!");
+        }
+
+        return loadedProvider;
+    }
+}
diff --git a/oap-libs-for-graalvm/log-analyzer-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/log-analyzer-for-graalvm/pom.xml
index 505b964..ac3465b 100644
--- a/oap-libs-for-graalvm/log-analyzer-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/log-analyzer-for-graalvm/pom.xml
@@ -36,6 +36,10 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>log-analyzer</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
@@ -60,6 +64,7 @@
                                 
<exclude>org/apache/skywalking/oap/log/analyzer/dsl/DSL.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/log/analyzer/dsl/DSL$*.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/log/analyzer/provider/LogAnalyzerModuleConfig.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/DSL.java
 
b/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/DSL.java
index d7efe57..f4d357b 100644
--- 
a/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/DSL.java
+++ 
b/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/dsl/DSL.java
@@ -27,6 +27,7 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import lombok.AccessLevel;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -49,6 +50,7 @@ import 
org.apache.skywalking.oap.server.library.module.ModuleStartException;
 public class DSL {
     private static final String MANIFEST_PATH = 
"META-INF/lal-scripts-by-hash.txt";
     private static volatile Map<String, String> SCRIPT_MAP;
+    private static final AtomicInteger LOADED_COUNT = new AtomicInteger();
 
     private final DelegatingScript script;
     private final FilterSpec filterSpec;
@@ -70,7 +72,8 @@ public class DSL {
             DelegatingScript script = (DelegatingScript) 
scriptClass.getDeclaredConstructor().newInstance();
             FilterSpec filterSpec = new FilterSpec(moduleManager, config);
             script.setDelegate(filterSpec);
-            log.debug("Loaded pre-compiled LAL script: {} -> {}", 
dslHash.substring(0, 12), className);
+            int count = LOADED_COUNT.incrementAndGet();
+            log.debug("Loaded pre-compiled LAL script [{}/{}]: {}", count, 
scriptMap.size(), className);
             return new DSL(script, filterSpec);
         } catch (ClassNotFoundException e) {
             throw new ModuleStartException(
diff --git 
a/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.java
 
b/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.java
new file mode 100644
index 0000000..04160f0
--- /dev/null
+++ 
b/oap-libs-for-graalvm/log-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/log/analyzer/provider/LALConfigs.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.log.analyzer.provider;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+
+import static 
org.apache.skywalking.oap.server.library.util.CollectionUtils.isEmpty;
+import static 
org.apache.skywalking.oap.server.library.util.StringUtil.isNotBlank;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * GraalVM replacement for upstream LALConfigs.
+ * Original: 
skywalking/oap-server/analyzer/log-analyzer/src/main/java/.../provider/LALConfigs.java
+ * Repackaged into log-analyzer-for-graalvm via maven-shade-plugin (replaces 
original .class in shaded JAR).
+ *
+ * Change: Complete rewrite of the static load() method. Loads pre-compiled 
LAL config data from JSON
+ * manifests (META-INF/config-data/{path}.json) instead of filesystem YAML 
files via ResourceUtils.getPathFiles().
+ * Why: The distro intentionally excludes raw YAML config directories — their 
DSL scripts are pre-compiled
+ * at build time. Config data (rule names, DSL strings, layers) is serialized 
as JSON by the precompiler.
+ */
+@Data
+@Slf4j
+public class LALConfigs {
+    private List<LALConfig> rules;
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    public static List<LALConfigs> load(final String path, final List<String> 
files) throws Exception {
+        if (isEmpty(files)) {
+            return Collections.emptyList();
+        }
+
+        checkArgument(isNotBlank(path), "path cannot be blank");
+
+        log.info("Loading LAL configs from pre-compiled distro ({})", path);
+
+        String resourcePath = "META-INF/config-data/" + path + ".json";
+        try (InputStream is = 
LALConfigs.class.getClassLoader().getResourceAsStream(resourcePath)) {
+            if (is == null) {
+                throw new ModuleStartException(
+                    "Pre-compiled config data not found: " + resourcePath
+                    + ". Ensure the precompiler has been run.");
+            }
+
+            Map<String, LALConfigs> allConfigs = MAPPER.readValue(
+                is, new TypeReference<Map<String, LALConfigs>>() { });
+
+            List<LALConfigs> result = allConfigs.entrySet().stream()
+                .filter(e -> files.contains(e.getKey()))
+                .map(Map.Entry::getValue)
+                .collect(Collectors.toList());
+
+            log.info("Loaded {} pre-compiled LAL configs from {} (filtered 
from {} available)",
+                result.size(), path, allConfigs.size());
+            return result;
+        } catch (ModuleStartException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ModuleStartException("Failed to load pre-compiled LAL 
config rules", e);
+        }
+    }
+}
diff --git a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/pom.xml
index 7ecc83a..3441483 100644
--- a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/pom.xml
@@ -36,6 +36,10 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>meter-analyzer</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
@@ -61,6 +65,7 @@
                                 
<exclude>org/apache/skywalking/oap/meter/analyzer/dsl/DSL$*.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression$*.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/DSL.java
 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/DSL.java
index cdf328d..d766fcf 100644
--- 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/DSL.java
+++ 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/DSL.java
@@ -25,6 +25,7 @@ import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import lombok.extern.slf4j.Slf4j;
 
 /**
@@ -40,6 +41,7 @@ import lombok.extern.slf4j.Slf4j;
 public final class DSL {
     private static final String MANIFEST_PATH = 
"META-INF/mal-groovy-scripts.txt";
     private static volatile Map<String, String> SCRIPT_MAP;
+    private static final AtomicInteger LOADED_COUNT = new AtomicInteger();
 
     public static Expression parse(final String metricName, final String 
expression) {
         if (metricName == null) {
@@ -59,7 +61,8 @@ public final class DSL {
         try {
             Class<?> scriptClass = Class.forName(className);
             DelegatingScript script = (DelegatingScript) 
scriptClass.getDeclaredConstructor().newInstance();
-            log.debug("Loaded pre-compiled MAL script: {} -> {}", metricName, 
className);
+            int count = LOADED_COUNT.incrementAndGet();
+            log.debug("Loaded pre-compiled MAL script [{}/{}]: {}", count, 
scriptMap.size(), metricName);
             return new Expression(metricName, expression, script);
         } catch (ClassNotFoundException e) {
             throw new IllegalStateException(
diff --git 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.java
 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.java
index b3c14b9..7e38792 100644
--- 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.java
+++ 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/FilterExpression.java
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
 import lombok.ToString;
 import lombok.extern.slf4j.Slf4j;
 
@@ -42,6 +43,7 @@ import lombok.extern.slf4j.Slf4j;
 public class FilterExpression {
     private static final String MANIFEST_PATH = 
"META-INF/mal-filter-scripts.properties";
     private static volatile Map<String, String> FILTER_MAP;
+    private static final AtomicInteger LOADED_COUNT = new AtomicInteger();
 
     private final String literal;
     private final Closure<Boolean> filterClosure;
@@ -62,7 +64,8 @@ public class FilterExpression {
             Class<?> scriptClass = Class.forName(className);
             Script filterScript = (Script) 
scriptClass.getDeclaredConstructor().newInstance();
             filterClosure = (Closure<Boolean>) filterScript.run();
-            log.debug("Loaded pre-compiled filter script for: {}", literal);
+            int count = LOADED_COUNT.incrementAndGet();
+            log.debug("Loaded pre-compiled filter script [{}/{}]: {}", count, 
filterMap.size(), literal);
         } catch (ClassNotFoundException e) {
             throw new IllegalStateException(
                 "Pre-compiled filter script class not found: " + className, e);
diff --git 
a/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.java
 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.java
new file mode 100644
index 0000000..6bb802f
--- /dev/null
+++ 
b/oap-libs-for-graalvm/meter-analyzer-for-graalvm/src/main/java/org/apache/skywalking/oap/meter/analyzer/prometheus/rule/Rules.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.meter.analyzer.prometheus.rule;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.UnexpectedException;
+
+/**
+ * GraalVM replacement for upstream Rules.
+ * Original: 
skywalking/oap-server/analyzer/meter-analyzer/src/main/java/.../prometheus/rule/Rules.java
+ * Repackaged into meter-analyzer-for-graalvm via maven-shade-plugin (replaces 
original .class in shaded JAR).
+ *
+ * Change: Complete rewrite. Loads pre-compiled rule data from JSON manifests
+ * (META-INF/config-data/{path}.json) instead of filesystem YAML files via 
ResourceUtils.getPath() + Files.walk().
+ * Why: The distro intentionally excludes raw YAML config directories — their 
Groovy expressions are
+ * pre-compiled at build time. Rule data (metric prefixes, expressions, rule 
names) is serialized as JSON
+ * by the precompiler for runtime wiring.
+ */
+@Slf4j
+public class Rules {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    public static List<Rule> loadRules(final String path) throws IOException {
+        return loadRules(path, Collections.emptyList());
+    }
+
+    public static List<Rule> loadRules(final String path, List<String> 
enabledRules) throws IOException {
+        log.info("Loading rules from pre-compiled distro ({})", path);
+
+        String resourcePath = "META-INF/config-data/" + path + ".json";
+        try (InputStream is = 
Rules.class.getClassLoader().getResourceAsStream(resourcePath)) {
+            if (is == null) {
+                throw new IOException(
+                    "Pre-compiled config data not found: " + resourcePath
+                    + ". Ensure the precompiler has been run.");
+            }
+
+            List<Rule> allRules = MAPPER.readValue(is, new 
TypeReference<List<Rule>>() { });
+
+            // Apply glob matching on rule names — same logic as upstream
+            Map<String, Boolean> formedEnabledRules = enabledRules.stream()
+                .map(rule -> {
+                    rule = rule.trim();
+                    if (rule.startsWith("/")) {
+                        rule = rule.substring(1);
+                    }
+                    if (!rule.endsWith(".yaml") && !rule.endsWith(".yml")) {
+                        return rule + "{.yaml,.yml}";
+                    }
+                    return rule;
+                })
+                .collect(Collectors.toMap(rule -> rule, $ -> false, (a, b) -> 
a));
+
+            List<Rule> filtered = allRules.stream()
+                .filter(rule -> {
+                    // Match rule name (relative path without extension) 
against enabled patterns
+                    // Add .yaml suffix for glob matching (same as upstream 
file-based matching)
+                    Path rulePath = Path.of(rule.getName() + ".yaml");
+                    return 
formedEnabledRules.keySet().stream().anyMatch(pattern -> {
+                        PathMatcher matcher = FileSystems.getDefault()
+                            .getPathMatcher("glob:" + pattern);
+                        boolean matches = matcher.matches(rulePath);
+                        if (matches) {
+                            formedEnabledRules.put(pattern, true);
+                        }
+                        return matches;
+                    });
+                })
+                .collect(Collectors.toList());
+
+            if (formedEnabledRules.containsValue(false)) {
+                List<String> rulesNotFound = 
formedEnabledRules.entrySet().stream()
+                    .filter(e -> !e.getValue())
+                    .map(Map.Entry::getKey)
+                    .collect(Collectors.toList());
+                throw new UnexpectedException(
+                    "Some configuration files of enabled rules are not found, 
enabled rules: "
+                    + rulesNotFound);
+            }
+
+            log.info("Loaded {} pre-compiled rules from {} (filtered from {} 
available)",
+                filtered.size(), path, allRules.size());
+            return filtered;
+        }
+    }
+}
diff --git a/oap-libs-for-graalvm/pom.xml b/oap-libs-for-graalvm/pom.xml
index 51bedb6..5466c42 100644
--- a/oap-libs-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/pom.xml
@@ -34,6 +34,7 @@
 
     <modules>
         <module>server-core-for-graalvm</module>
+        <module>library-module-for-graalvm</module>
         <module>library-util-for-graalvm</module>
         <module>meter-analyzer-for-graalvm</module>
         <module>log-analyzer-for-graalvm</module>
diff --git a/oap-libs-for-graalvm/server-core-for-graalvm/pom.xml 
b/oap-libs-for-graalvm/server-core-for-graalvm/pom.xml
index deba20d..4ccd3bd 100644
--- a/oap-libs-for-graalvm/server-core-for-graalvm/pom.xml
+++ b/oap-libs-for-graalvm/server-core-for-graalvm/pom.xml
@@ -66,6 +66,7 @@
                                 
<exclude>org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem$*.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.class</exclude>
                                 
<exclude>org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService$*.class</exclude>
+                                
<exclude>org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.class</exclude>
                             </excludes>
                         </filter>
                     </filters>
diff --git 
a/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
index a946708..335f26c 100644
--- 
a/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
+++ 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/config/HierarchyDefinitionService.java
@@ -17,12 +17,12 @@
 
 package org.apache.skywalking.oap.server.core.config;
 
-import groovy.lang.Closure;
 import java.io.FileNotFoundException;
 import java.io.Reader;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.BiFunction;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.core.CoreModuleConfig;
@@ -37,54 +37,44 @@ import static java.util.stream.Collectors.toMap;
 /**
  * Same-FQCN replacement of upstream HierarchyDefinitionService.
  *
- * <p>Replaces {@code GroovyShell.evaluate()} in {@code MatchingRule} with
- * pre-built Java-backed {@link Closure} objects. Eliminates runtime Groovy
- * compilation, which is not available in GraalVM native image.
+ * <p>Replaces {@code GroovyShell.evaluate()} with pre-built Java
+ * {@link BiFunction} implementations. Eliminates runtime Groovy
+ * compilation and the Groovy runtime dependency entirely.
  *
- * <p>The 4 matching rules from {@code hierarchy-definition.yml} are 
implemented
- * as anonymous {@code Closure<Boolean>} subclasses in {@link #RULE_REGISTRY}.
+ * <p>The 4 matching rules from {@code hierarchy-definition.yml} are
+ * implemented as lambda expressions in {@link #RULE_REGISTRY}.
  * Unknown rule names fail fast at startup.
  */
 @Slf4j
 public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.server.library.module.Service {
 
     /**
-     * Pre-built matching rule closures keyed by rule name from 
hierarchy-definition.yml.
-     * Each closure takes two Service arguments (upper, lower) and returns 
Boolean.
+     * Pre-built matching rules keyed by rule name from 
hierarchy-definition.yml.
+     * Each function takes two Service arguments (upper, lower) and returns 
Boolean.
      */
-    private static final Map<String, Closure<Boolean>> RULE_REGISTRY;
+    private static final Map<String, BiFunction<Service, Service, Boolean>> 
RULE_REGISTRY;
 
     static {
         RULE_REGISTRY = new HashMap<>();
 
         // name: "{ (u, l) -> u.name == l.name }"
-        RULE_REGISTRY.put("name", new Closure<Boolean>(null) {
-            public Boolean doCall(final Service u, final Service l) {
-                return Objects.equals(u.getName(), l.getName());
-            }
-        });
+        RULE_REGISTRY.put("name", (u, l) -> Objects.equals(u.getName(), 
l.getName()));
 
         // short-name: "{ (u, l) -> u.shortName == l.shortName }"
-        RULE_REGISTRY.put("short-name", new Closure<Boolean>(null) {
-            public Boolean doCall(final Service u, final Service l) {
-                return Objects.equals(u.getShortName(), l.getShortName());
-            }
-        });
+        RULE_REGISTRY.put("short-name", (u, l) -> 
Objects.equals(u.getShortName(), l.getShortName()));
 
         // lower-short-name-remove-ns:
         // "{ (u, l) -> { if(l.shortName.lastIndexOf('.') > 0)
         //     return u.shortName == l.shortName.substring(0, 
l.shortName.lastIndexOf('.'));
         //     return false; } }"
-        RULE_REGISTRY.put("lower-short-name-remove-ns", new 
Closure<Boolean>(null) {
-            public Boolean doCall(final Service u, final Service l) {
-                int dot = l.getShortName().lastIndexOf('.');
-                if (dot > 0) {
-                    return Objects.equals(
-                        u.getShortName(),
-                        l.getShortName().substring(0, dot));
-                }
-                return false;
+        RULE_REGISTRY.put("lower-short-name-remove-ns", (u, l) -> {
+            int dot = l.getShortName().lastIndexOf('.');
+            if (dot > 0) {
+                return Objects.equals(
+                    u.getShortName(),
+                    l.getShortName().substring(0, dot));
             }
+            return false;
         });
 
         // lower-short-name-with-fqdn:
@@ -92,16 +82,14 @@ public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.ser
         //     return u.shortName.substring(0, u.shortName.lastIndexOf(':'))
         //         == l.shortName.concat('.svc.cluster.local');
         //     return false; } }"
-        RULE_REGISTRY.put("lower-short-name-with-fqdn", new 
Closure<Boolean>(null) {
-            public Boolean doCall(final Service u, final Service l) {
-                int colon = u.getShortName().lastIndexOf(':');
-                if (colon > 0) {
-                    return Objects.equals(
-                        u.getShortName().substring(0, colon),
-                        l.getShortName() + ".svc.cluster.local");
-                }
-                return false;
+        RULE_REGISTRY.put("lower-short-name-with-fqdn", (u, l) -> {
+            int colon = u.getShortName().lastIndexOf(':');
+            if (colon > 0) {
+                return Objects.equals(
+                    u.getShortName().substring(0, colon),
+                    l.getShortName() + ".svc.cluster.local");
             }
+            return false;
         });
     }
 
@@ -177,13 +165,13 @@ public class HierarchyDefinitionService implements 
org.apache.skywalking.oap.ser
     public static class MatchingRule {
         private final String name;
         private final String expression;
-        private final Closure<Boolean> closure;
+        private final BiFunction<Service, Service, Boolean> matcher;
 
         public MatchingRule(final String name, final String expression) {
             this.name = name;
             this.expression = expression;
-            this.closure = RULE_REGISTRY.get(name);
-            if (this.closure == null) {
+            this.matcher = RULE_REGISTRY.get(name);
+            if (this.matcher == null) {
                 throw new IllegalArgumentException(
                     "Unknown hierarchy matching rule: " + name
                         + ". Known rules: " + RULE_REGISTRY.keySet());
diff --git 
a/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
new file mode 100644
index 0000000..a2c0b16
--- /dev/null
+++ 
b/oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/org/apache/skywalking/oap/server/core/hierarchy/HierarchyService.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.server.core.hierarchy;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.CoreModuleConfig;
+import org.apache.skywalking.oap.server.core.analysis.Layer;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import org.apache.skywalking.oap.server.core.config.HierarchyDefinitionService;
+import 
org.apache.skywalking.oap.server.core.hierarchy.instance.InstanceHierarchyRelation;
+import 
org.apache.skywalking.oap.server.core.hierarchy.service.ServiceHierarchyRelation;
+import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
+import org.apache.skywalking.oap.server.core.query.type.Service;
+import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import 
org.apache.skywalking.oap.server.library.util.RunnableWithExceptionProtection;
+
+/**
+ * Same-FQCN replacement of upstream HierarchyService.
+ *
+ * <p>Uses {@code MatchingRule.getMatcher().apply()} (BiFunction) instead of
+ * upstream's {@code getClosure().call()} (Groovy Closure), eliminating the
+ * Groovy runtime dependency.
+ */
+@Slf4j
+public class HierarchyService implements 
org.apache.skywalking.oap.server.library.module.Service {
+    private final ModuleManager moduleManager;
+    private final boolean isEnableHierarchy;
+    private SourceReceiver sourceReceiver;
+    private MetadataQueryService metadataQueryService;
+    private Map<String, Map<String, HierarchyDefinitionService.MatchingRule>> 
hierarchyDefinition;
+
+    public HierarchyService(ModuleManager moduleManager, CoreModuleConfig 
moduleConfig) {
+        this.moduleManager = moduleManager;
+        this.isEnableHierarchy = moduleConfig.isEnableHierarchy();
+    }
+
+    private SourceReceiver getSourceReceiver() {
+        if (sourceReceiver == null) {
+            this.sourceReceiver = 
moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class);
+        }
+        return sourceReceiver;
+
+    }
+
+    private Map<String, Map<String, HierarchyDefinitionService.MatchingRule>> 
getHierarchyDefinition() {
+        if (hierarchyDefinition == null) {
+            hierarchyDefinition = moduleManager.find(CoreModule.NAME)
+                                               .provider()
+                                               
.getService(HierarchyDefinitionService.class).getHierarchyDefinition();
+        }
+        return hierarchyDefinition;
+    }
+
+    private MetadataQueryService getMetadataQueryService() {
+        if (metadataQueryService == null) {
+            this.metadataQueryService = moduleManager.find(CoreModule.NAME)
+                                                     .provider()
+                                                     
.getService(MetadataQueryService.class);
+        }
+        return metadataQueryService;
+    }
+
+    public void toServiceHierarchyRelation(String upperServiceName,
+                                           Layer upperServiceLayer,
+                                           String lowerServiceName,
+                                           Layer lowerServiceLayer) {
+        if (!this.isEnableHierarchy) {
+            return;
+        }
+        Map<String, HierarchyDefinitionService.MatchingRule> lowerLayers = 
getHierarchyDefinition().get(upperServiceLayer.name());
+        if (lowerLayers == null || 
!lowerLayers.containsKey(lowerServiceLayer.name())) {
+            log.error("upperServiceLayer " + upperServiceLayer.name() + " or 
lowerServiceLayer " + lowerServiceLayer.name()
+                          + " is not defined in hierarchy-definition.yml.");
+            return;
+        }
+        autoMatchingServiceRelation(upperServiceName, upperServiceLayer, 
lowerServiceName, lowerServiceLayer);
+    }
+
+    public void toInstanceHierarchyRelation(String upperInstanceName,
+                                            String upperServiceName,
+                                            Layer upperServiceLayer,
+                                            String lowerInstanceName,
+                                            String lowerServiceName,
+                                            Layer lowerServiceLayer) {
+        if (!this.isEnableHierarchy) {
+            return;
+        }
+        Map<String, HierarchyDefinitionService.MatchingRule> lowerLayers = 
getHierarchyDefinition().get(upperServiceLayer.name());
+        if (lowerLayers == null || 
!lowerLayers.containsKey(lowerServiceLayer.name())) {
+            log.error("upperServiceLayer " + upperServiceLayer.name() + " or 
lowerServiceLayer " + lowerServiceLayer.name()
+                          + " is not defined in hierarchy-definition.yml.");
+            return;
+        }
+
+        buildInstanceHierarchyRelation(upperInstanceName, upperServiceName, 
upperServiceLayer, lowerInstanceName,
+                                           lowerServiceName, 
lowerServiceLayer);
+    }
+
+    public void startAutoMatchingServiceHierarchy() {
+        if (!this.isEnableHierarchy) {
+            return;
+        }
+        Executors.newSingleThreadScheduledExecutor()
+                 .scheduleWithFixedDelay(
+                     new 
RunnableWithExceptionProtection(this::autoMatchingServiceRelation, t -> 
log.error(
+                         "Scheduled auto matching service hierarchy from 
service traffic failure.", t)), 30, 20, TimeUnit.SECONDS);
+    }
+
+    private void autoMatchingServiceRelation(String upperServiceName,
+                                             Layer upperServiceLayer,
+                                             String lowerServiceName,
+                                             Layer lowerServiceLayer) {
+        ServiceHierarchyRelation serviceHierarchy = new 
ServiceHierarchyRelation();
+        serviceHierarchy.setServiceName(upperServiceName);
+        serviceHierarchy.setServiceLayer(upperServiceLayer);
+        serviceHierarchy.setRelatedServiceName(lowerServiceName);
+        serviceHierarchy.setRelatedServiceLayer(lowerServiceLayer);
+        
serviceHierarchy.setTimeBucket(TimeBucket.getMinuteTimeBucket(System.currentTimeMillis()));
+        this.getSourceReceiver().receive(serviceHierarchy);
+    }
+
+    private void buildInstanceHierarchyRelation(String upperInstanceName,
+                                                String upperServiceName,
+                                                Layer upperServiceLayer,
+                                                String lowerInstanceName,
+                                                String lowerServiceName,
+                                                Layer lowerServiceLayer) {
+        InstanceHierarchyRelation instanceHierarchy = new 
InstanceHierarchyRelation();
+        instanceHierarchy.setInstanceName(upperInstanceName);
+        instanceHierarchy.setServiceName(upperServiceName);
+        instanceHierarchy.setServiceLayer(upperServiceLayer);
+        instanceHierarchy.setRelatedInstanceName(lowerInstanceName);
+        instanceHierarchy.setRelatedServiceName(lowerServiceName);
+        instanceHierarchy.setRelatedServiceLayer(lowerServiceLayer);
+        
instanceHierarchy.setTimeBucket(TimeBucket.getMinuteTimeBucket(System.currentTimeMillis()));
+        this.getSourceReceiver().receive(instanceHierarchy);
+    }
+
+    private void autoMatchingServiceRelation() {
+        List<Service> allServices = getMetadataQueryService().listAllServices()
+                                                             .values()
+                                                             .stream()
+                                                             
.flatMap(List::stream)
+                                                             
.collect(Collectors.toList());
+        if (allServices.size() > 1) {
+            for (int i = 0; i < allServices.size(); i++) {
+                for (int j = i + 1; j < allServices.size(); j++) {
+                    Service service = allServices.get(i);
+                    Service comparedService = allServices.get(j);
+                    String serviceLayer = 
service.getLayers().iterator().next();
+                    String comparedServiceLayer = 
comparedService.getLayers().iterator().next();
+                    Map<String, HierarchyDefinitionService.MatchingRule> 
lowerLayers = getHierarchyDefinition().get(
+                        serviceLayer);
+                    Map<String, HierarchyDefinitionService.MatchingRule> 
comparedLowerLayers = getHierarchyDefinition().get(
+                        comparedServiceLayer);
+                    if (lowerLayers != null && 
lowerLayers.get(comparedServiceLayer) != null) {
+                        try {
+                            if (lowerLayers.get(comparedServiceLayer)
+                                           .getMatcher()
+                                           .apply(service, comparedService)) {
+                                autoMatchingServiceRelation(service.getName(), 
Layer.nameOf(serviceLayer),
+                                                            
comparedService.getName(),
+                                                            
Layer.nameOf(comparedServiceLayer)
+                                );
+                            }
+                        } catch (Throwable e) {
+                            log.error(
+                                "Auto matching service hierarchy from service 
traffic failure. Upper layer {}, lower layer {}, expression {}",
+                                serviceLayer,
+                                comparedServiceLayer,
+                                
lowerLayers.get(comparedServiceLayer).getExpression(), e
+                            );
+                        }
+
+                    } else if (comparedLowerLayers != null && 
comparedLowerLayers.get(serviceLayer) != null) {
+                        try {
+                            if (comparedLowerLayers.get(serviceLayer)
+                                                   .getMatcher()
+                                                   .apply(comparedService, 
service)) {
+                                autoMatchingServiceRelation(
+                                    comparedService.getName(),
+                                    Layer.nameOf(comparedServiceLayer),
+                                    service.getName(),
+                                    Layer.nameOf(serviceLayer)
+                                );
+                            }
+                        } catch (Throwable e) {
+                            log.error(
+                                "Auto matching service hierarchy from service 
traffic failure. Upper layer {}, lower layer {}, expression {}",
+                                comparedServiceLayer,
+                                serviceLayer,
+                                
comparedLowerLayers.get(serviceLayer).getExpression(), e
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
index b9f3955..85d9fff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,12 @@
         <checkstyle.version>6.18</checkstyle.version>
         <checkstyle.fails.on.error>true</checkstyle.fails.on.error>
         <junit.version>5.9.2</junit.version>
+        <!-- Versions aligned with upstream skywalking transitive deps -->
+        <groovy.version>5.0.3</groovy.version>
+        <commons-text.version>1.4</commons-text.version>
+        <joda-time.version>2.10.5</joda-time.version>
+        <mockito.version>5.11.0</mockito.version>
+        <powermock.version>2.0.9</powermock.version>
     </properties>
 
     <modules>
@@ -52,6 +58,22 @@
 
     <dependencyManagement>
         <dependencies>
+            <!-- Import upstream BOM to align third-party dependency versions 
-->
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>oap-server-bom</artifactId>
+                <version>${skywalking.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- Proto stubs (OpenTelemetry, Envoy, etc.) -->
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>receiver-proto</artifactId>
+                <version>${skywalking.version}</version>
+            </dependency>
+
             <!-- Storage: BanyanDB -->
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
@@ -194,6 +216,11 @@
                 
<artifactId>skywalking-async-profiler-receiver-plugin</artifactId>
                 <version>${skywalking.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-async-profiler-jfr-parser</artifactId>
+                <version>${skywalking.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>skywalking-pprof-receiver-plugin</artifactId>
@@ -336,6 +363,11 @@
                 <artifactId>server-core-for-graalvm</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.skywalking</groupId>
+                <artifactId>library-module-for-graalvm</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.skywalking</groupId>
                 <artifactId>library-util-for-graalvm</artifactId>
@@ -400,6 +432,27 @@
                 <scope>provided</scope>
             </dependency>
 
+            <!--
+              Transitive deps of provided-scope upstream JARs that are
+              still needed at runtime (Groovy for pre-compiled MAL scripts,
+              commons-text for MetricConvert, joda-time for alarm formatting).
+            -->
+            <dependency>
+                <groupId>org.apache.groovy</groupId>
+                <artifactId>groovy</artifactId>
+                <version>${groovy.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-text</artifactId>
+                <version>${commons-text.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>joda-time</groupId>
+                <artifactId>joda-time</artifactId>
+                <version>${joda-time.version}</version>
+            </dependency>
+
             <!-- Test -->
             <dependency>
                 <groupId>org.junit.jupiter</groupId>
@@ -407,6 +460,24 @@
                 <version>${junit.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-core</artifactId>
+                <version>${mockito.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-junit-jupiter</artifactId>
+                <version>${mockito.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.powermock</groupId>
+                <artifactId>powermock-reflect</artifactId>
+                <version>${powermock.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

Reply via email to