-
Notifications
You must be signed in to change notification settings - Fork 0
<feature>[dependencies]: Upgrade java version to 17 #3280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 5.5.6
Are you sure you want to change the base?
Conversation
ZQLImpact Change-Id: I656f6963726b77727363656d756465766b6a7a6a
Walkthrough此拉取请求添加 Java 17 兼容性支持、将废弃的反射 API 迁移至现代替代方案、补充架构和构建加速文档,并调整 Groovy 类型注解以适应新版本。 Changes
Estimated Code Review Effort🎯 3 (中等) | ⏱️ ~25 分钟 Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.40.5)compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.javaComment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
🤖 Fix all issues with AI agents
In `@build/debug.sh`:
- Around line 11-16: Replace the Chinese comment "加载Java 17 JVM参数" with an
English comment describing the same purpose (e.g., "Load Java 17 JVM options")
so comments are consistently in English; update the comment near the
jvm_options_file and jvm_options declarations to use the corrected English text.
- Line 18: 第 18 行条件判断使用了非 POSIX 的比较运算符 "=="(在 if [ x"$is_suspend" == x"true" ];
then),会在严格的 sh 实现中失败;将该比较改为单等号 "="(即使用 if [ x"$is_suspend" = x"true" ];
then)以确保与 POSIX sh(dash 等)兼容并提高可移植性,保留变量前的 x 前缀和引号以防空值或特殊字符。
In `@build/fix-groovy-compiler.sh`:
- Around line 3-15: The script contains Chinese comments and echo output (lines
around the header and description) that must be converted to English to match
repo conventions; update the top comment block and all echo strings (e.g., the
header lines currently printed with echo
"==========================================" and the "批量修复Groovy编译配置" message)
to clear, correctly spelled English, and ensure inline comments (above set -e,
SCRIPT_DIR, PROJECT_ROOT) are rewritten in English as well so all user-facing
and inline text in this script (fix-groovy-compiler.sh) uses English only.
- Around line 95-266: The script contains Chinese text and uses an unquoted
heredoc for the embedded Python block; replace all Chinese comments and
user-facing messages with English and switch the heredoc to a single-quoted form
(use <<'PYTHON_SCRIPT') so the shell will not expand variables inside the block,
and pass the FILE path into the Python script via an exported environment
variable (or as an argument) instead of relying on unescaped expansions; update
prints like "✅ 修复完成"/"⚠️ 未找到需要替换的内容" and shell echoes "✅ 修复成功"/"⚠️
修复失败或无需修复,请手动检查" to clear English equivalents, ensure the Python logic
(functions/variables: pattern, pattern2, replace_plugin, lines/new_lines,
version detection using version_line and version_match) continues to work with
the quoted heredoc and the existing escaped ${project.java.version} strings, and
verify the script exits with the same status behavior.
In `@build/verify-java17.sh`:
- Around line 65-76: The current if-check uses a pipeline (mvn test ... | tee
/tmp/java17-test.log) so tee hides mvn's exit code; enable proper failure
detection by either enabling pipefail (set -o pipefail before the pipeline) or
capture mvn's exit with PIPESTATUS after the pipeline (e.g., inspect
${PIPESTATUS[0]}), then use that exit code to decide the if/else branch for the
mvn invocation shown in the mvn test -pl utils,abstraction ... 2>&1 | tee
/tmp/java17-test.log command and subsequent TEST_FAILED logic.
- Around line 1-98: The script contains Chinese comments and output strings;
replace all Chinese text with clear English equivalents (e.g., change header
echoes, section markers "[1/6]".."[6/6]", comment lines, error messages and
suggestions) while preserving logic and variable names like JAVA_VERSION,
SPRING_VERSION, HIBERNATE_VERSION, ASPECTJ_VERSION, GROOVY_VERSION and temp log
/tmp/java17-test.log; update messages for success/failure (e.g., "❌ 错误: 需要Java
17..." → "ERROR: Java 17 is required, current version: ...", "✓ 核心模块编译成功" → "OK:
core modules compiled") and translate all other echoed guidance and comments to
idiomatic, correctly spelled English.
In `@build/zstack`:
- Line 23: Replace the Chinese comment "# 加载Java 17 JVM参数" with an English
equivalent (e.g., "# Load Java 17 JVM parameters" or "# Load Java 17 JVM
options") in build/zstack; ensure the updated comment text for the JVM parameter
section uses correct English and scan the surrounding comments in the same file
for any other Chinese text to convert to English as well.
In `@build/zstack-debug`:
- Line 23: The comment at line with "# 加载Java 17 JVM参数" must be converted to
English to follow the project's language guidelines; replace the Chinese comment
with an appropriate English equivalent such as "Load Java 17 JVM parameters" or
"Load Java 17 JVM options" in the build/zstack-debug file so all comments and
messages are in correct English and consistent across the codebase.
- Around line 29-30: The script defines the JVM options into a misspelled
variable javaOptitons but then invokes java using javaOptions, so the JVM flags
are never passed; fix by correcting the variable name so both places use the
same identifier (either rename javaOptitons to javaOptions where it’s defined or
change the invocation to use javaOptitons) and ensure the value includes the
intended flags (-Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError
-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y) so the JVM
receives the parameters.
In `@conf/jvm-options-java17.conf`:
- Around line 1-18: Replace all Chinese comments in this JVM options file with
clear English comments: change the file header comment to "Java 17 module system
configuration", the reflective-access note "开放反射访问(226处setAccessible需要)" to
"Open reflective access (required for setAccessible usages)", the internal-API
export note "导出内部API(sun.misc.Signal需要)" to "Export internal APIs (required for
sun.misc.Signal)", the Hibernate note "Hibernate需要" to "Required by Hibernate",
and the AspectJ note "AspectJ需要" to "Required by AspectJ"; keep the option lines
(--add-opens, --add-exports, --add-opens java.base/java.time, --add-opens
java.base/java.lang.invoke) unchanged.
In `@docs/ARCHITECTURE.md`:
- Around line 1-1199: The document "ZStack 后端架构索引" is in Chinese but the repo
requires English-only content; update this ARCHITECTURE.md by providing an
English version (either replace the Chinese text or add a full English
translation alongside the Chinese), ensuring all headings, descriptions, table
entries, code comments/examples and appended notes (e.g., "文档版本", "最后更新") are
converted to proper English, and keep structural identifiers (like
class/interface names: CloudBus, DatabaseFacade, ThreadFacade, FlowChain,
GlobalConfig, etc.) unchanged so readers can locate code references.
In `@docs/BUILD-ACCELERATION.md`:
- Around line 1-141: The document "ZStack 构建加速指南" is written in Chinese but the
repo requires English-only documentation; please convert this file to English
(or add a complete English version alongside the Chinese) so all headings (e.g.,
"ZStack 构建加速指南"), section titles, prose, and any inline comments are in correct
English and free of spelling errors; keep command examples and flags unchanged,
preserve technical details (mvnd/mvn usage, profiles, flags like -P premium,
-Dmevoco.skip.obfuscate=true, .mvn/jvm.config settings, and plugin notes such as
gmavenplus fork) and, if you retain the Chinese version, add a clear bilingual
header indicating both languages and ensure filenames/links referenced in the
text remain consistent.
In `@longjob/src/main/java/org/zstack/longjob/LongJobFactoryImpl.java`:
- Around line 54-57: The catch block in LongJobFactoryImpl that handles
InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException currently calls e.printStackTrace(); replace this with
a proper logger call (e.g., logger.error("Failed to instantiate LongJob via
reflection for " + it.getName(), e)) so the exception is recorded via the class
logger; update the catch to log the exception and any contextual info (the
constructor/type or variable job) instead of printing the stack trace.
🧹 Nitpick comments (2)
runMavenProfile (1)
502-502: 建议验证并行构建的兼容性。添加
-T 1C启用 Maven 并行构建(每 CPU 核心 1 个线程)可以显著加快构建速度,但需要确保:
- 所有模块间依赖已正确声明
- 使用的 Maven 插件是线程安全的
- 没有资源竞争问题(如文件锁、端口占用等)
建议在合并前确认并行构建在 CI 环境中测试通过。
tag/src/main/java/org/zstack/tag/PatternedSystemTag.java (1)
126-136: 反射更新正确,但可考虑使用更精确的异常类型。将 catch 从特定异常类型扩展为通用
Exception会降低异常处理的精确性。建议保持与其他文件一致的异常处理模式。♻️ 建议的优化方案
public String hideSensitiveInfo(String tag) { Class<? extends SensitiveTagOutputHandler> clz = this.annotation.customizeOutput(); String result = tag; try { SensitiveTagOutputHandler sensitiveOutputHandler = clz.getConstructor().newInstance(); result = sensitiveOutputHandler.desensitizeTag(this, tag); - } catch (Exception e) { + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | java.lang.reflect.InvocationTargetException e) { logger.warn("exception happened :", e); } return result; }
| # 加载Java 17 JVM参数 | ||
| jvm_options_file="$conf_dir/jvm-options-java17.conf" | ||
| jvm_options="" | ||
| if [ -f "$jvm_options_file" ]; then | ||
| jvm_options=$(cat "$jvm_options_file" | grep -v '^#' | tr '\n' ' ') | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 11 的中文注释请改为英文
注释语言需统一为英文。
As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🤖 Prompt for AI Agents
In `@build/debug.sh` around lines 11 - 16, Replace the Chinese comment "加载Java 17
JVM参数" with an English comment describing the same purpose (e.g., "Load Java 17
JVM options") so comments are consistently in English; update the comment near
the jvm_options_file and jvm_options declarations to use the corrected English
text.
| jvm_options=$(cat "$jvm_options_file" | grep -v '^#' | tr '\n' ' ') | ||
| fi | ||
|
|
||
| if [ x"$is_suspend" == x"true" ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n build/debug.sh | sed -n '10,25p'Repository: MatheMatrix/zstack
Length of output: 742
🏁 Script executed:
# 检查是否存在 build/debug.sh 文件
ls -la build/debug.sh 2>&1 | head -20Repository: MatheMatrix/zstack
Length of output: 125
🌐 Web query:
POSIX sh test operator == vs = compatibility dash busybox
💡 Result:
- POSIX
sh/ POSIXtest([ ... ]) string equality operator is=(and!=for inequality).==is not required by POSIX. Use:if [ "$a" = "$b" ]; then ...; fi.[1] dash(Debian Almquist shell) is strict here:[ x == x ]fails with[: unexpected operator, so==is not compatible withdashscripts.[2]- BusyBox
ash/shoften accepts==in[ ... ]as an extension, so[ x == x ]may work there—but that’s exactly why it’s a portability trap: it works on BusyBox but breaks ondash.[2] - Some
testimplementations (e.g., GNU coreutilstest) document==as a non-portable synonym for=.[3] [[ ... ]]is not POSIXsh(and its behavior varies); BusyBox only supports it in some builds and with limited compatibility options, so don’t use it in scripts that must run underdash/POSIXsh.[4]
Rule for maximum compatibility (dash + BusyBox + POSIX): use = inside [ ... ], not ==.[1][2]
Sources:
[1] man7 test(1) (string tests: STRING1 = STRING2) (man7.org)
[2] Unix & Linux SE showing dash rejects == while BusyBox accepts it (unix.stackexchange.com)
[3] GNU coreutils manual: == is a synonym for = but “not as portable” (gnu.org)
[4] Unix & Linux SE on BusyBox [[...]] support being optional/limited (unix.stackexchange.com)
Citations:
- 1: https://www.man7.org/linux/man-pages/man1/test.1.html?utm_source=openai
- 2: https://unix.stackexchange.com/questions/382003/what-are-the-differences-between-and-in-conditional-expressions?utm_source=openai
- 3: https://www.gnu.org/s/coreutils/manual/html_node/String-tests.html?utm_source=openai
- 4: https://unix.stackexchange.com/questions/297086/how-to-check-variable-existence-and-compare-with-the-string-in-busybox?utm_source=openai
在 POSIX sh 中应使用单等号 = 而非 ==
第 18 行使用了 == 作为条件比较操作符,但 POSIX 标准 sh 规定应使用单等号 =。在 dash(Debian Almquist shell)等严格遵循 POSIX 标准的 shell 实现中,== 会导致错误 [: unexpected operator。此外,== 是一些 shell 的非标准扩展,使用它会降低脚本的可移植性。
🔧 建议修复
-if [ x"$is_suspend" == x"true" ]; then
+if [ x"$is_suspend" = x"true" ]; then📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ x"$is_suspend" == x"true" ]; then | |
| if [ x"$is_suspend" = x"true" ]; then |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 18-18: In POSIX sh, == in place of = is undefined.
(SC3014)
🤖 Prompt for AI Agents
In `@build/debug.sh` at line 18, 第 18 行条件判断使用了非 POSIX 的比较运算符 "=="(在 if [
x"$is_suspend" == x"true" ]; then),会在严格的 sh 实现中失败;将该比较改为单等号 "="(即使用 if [
x"$is_suspend" = x"true" ]; then)以确保与 POSIX sh(dash 等)兼容并提高可移植性,保留变量前的 x
前缀和引号以防空值或特殊字符。
| # 批量修复Groovy编译配置脚本 | ||
| # 用于将groovy-eclipse-compiler替换为标准Java编译器或GMavenPlus | ||
|
|
||
| set -e | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" | ||
|
|
||
| cd "$PROJECT_ROOT" | ||
|
|
||
| echo "==========================================" | ||
| echo "批量修复Groovy编译配置" | ||
| echo "==========================================" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
脚本注释与输出请改为英文
Line 3-15 等处包含中文注释/输出,与当前仓库规范不一致,请统一为英文。
As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🤖 Prompt for AI Agents
In `@build/fix-groovy-compiler.sh` around lines 3 - 15, The script contains
Chinese comments and echo output (lines around the header and description) that
must be converted to English to match repo conventions; update the top comment
block and all echo strings (e.g., the header lines currently printed with echo
"==========================================" and the "批量修复Groovy编译配置" message)
to clear, correctly spelled English, and ensure inline comments (above set -e,
SCRIPT_DIR, PROJECT_ROOT) are rewritten in English as well so all user-facing
and inline text in this script (fix-groovy-compiler.sh) uses English only.
| # 使用Python进行精确替换(因为sed处理多行和缩进比较复杂) | ||
| python3 <<PYTHON_SCRIPT | ||
| import re | ||
| import sys | ||
|
|
||
| file_path = "$FILE" | ||
|
|
||
| with open(file_path, 'r', encoding='utf-8') as f: | ||
| content = f.read() | ||
|
|
||
| # 匹配groovy-eclipse-compiler配置块 | ||
| # 匹配从<plugin>开始到</plugin>结束,包含groovy-eclipse-compiler的整个块 | ||
| pattern = r'''\s*<plugin>\s* | ||
| \s*<groupId>org\.apache\.maven\.plugins</groupId>\s* | ||
| \s*<artifactId>maven-compiler-plugin</artifactId>\s* | ||
| \s*<version>.*?</version>\s* | ||
| \s*<configuration>\s* | ||
| \s*<compilerId>groovy-eclipse-compiler</compilerId>\s* | ||
| \s*<source>\$\{project\.java\.version\}</source>\s* | ||
| \s*<target>\$\{project\.java\.version\}</target>\s* | ||
| \s*<debuglevel>lines,vars,source</debuglevel>\s* | ||
| \s*<debug>true</debug>\s* | ||
| \s*</configuration>\s* | ||
| \s*<dependencies>\s* | ||
| \s*<dependency>\s* | ||
| \s*<groupId>org\.codehaus\.groovy</groupId>\s* | ||
| \s*<artifactId>groovy-eclipse-compiler</artifactId>\s* | ||
| \s*<version>.*?</version>\s* | ||
| \s*</dependency>\s* | ||
| \s*<dependency>\s* | ||
| \s*<groupId>org\.codehaus\.groovy</groupId>\s* | ||
| \s*<artifactId>groovy-eclipse-batch</artifactId>\s* | ||
| \s*<version>.*?</version>\s* | ||
| \s*</dependency>\s* | ||
| \s*</dependencies>\s* | ||
| \s*</plugin>''' | ||
|
|
||
| # 更灵活的匹配模式(处理不同的缩进和换行) | ||
| pattern2 = r'''(\s*)<plugin>\s* | ||
| \1<groupId>org\.apache\.maven\.plugins</groupId>\s* | ||
| \1<artifactId>maven-compiler-plugin</artifactId>\s* | ||
| \1<version>([^<]+)</version>\s* | ||
| \1<configuration>\s* | ||
| \1\s*<compilerId>groovy-eclipse-compiler</compilerId>\s* | ||
| \1\s*<source>\$\{project\.java\.version\}</source>\s* | ||
| \1\s*<target>\$\{project\.java\.version\}</target>\s* | ||
| \1\s*<debuglevel>lines,vars,source</debuglevel>\s* | ||
| \1\s*<debug>true</debug>\s* | ||
| \1</configuration>\s* | ||
| \1<dependencies>\s* | ||
| \1\s*<dependency>\s* | ||
| \1\s*<groupId>org\.codehaus\.groovy</groupId>\s* | ||
| \1\s*<artifactId>groovy-eclipse-compiler</artifactId>\s* | ||
| \1\s*<version>[^<]+</version>\s* | ||
| \1\s*</dependency>\s* | ||
| \1\s*<dependency>\s* | ||
| \1\s*<groupId>org\.codehaus\.groovy</groupId>\s* | ||
| \1\s*<artifactId>groovy-eclipse-batch</artifactId>\s* | ||
| \1\s*<version>[^<]+</version>\s* | ||
| \1\s*</dependency>\s* | ||
| \1</dependencies>\s* | ||
| \1</plugin>''' | ||
|
|
||
| # 尝试匹配并替换 | ||
| def replace_plugin(match): | ||
| indent = match.group(1) | ||
| version = match.group(2).strip() | ||
| replacement = f'''{indent}<plugin> | ||
| {indent} <groupId>org.apache.maven.plugins</groupId> | ||
| {indent} <artifactId>maven-compiler-plugin</artifactId> | ||
| {indent} <version>{version}</version> | ||
| {indent} <configuration> | ||
| {indent} <source>${{project.java.version}}</source> | ||
| {indent} <target>${{project.java.version}}</target> | ||
| {indent} <debug>true</debug> | ||
| {indent} <parameters>true</parameters> | ||
| {indent} </configuration> | ||
| {indent}</plugin>''' | ||
| return replacement | ||
|
|
||
| # 使用更简单的方法:逐行处理 | ||
| lines = content.split('\n') | ||
| new_lines = [] | ||
| i = 0 | ||
| in_plugin = False | ||
| in_config = False | ||
| in_dependencies = False | ||
| plugin_start = -1 | ||
| indent = "" | ||
|
|
||
| while i < len(lines): | ||
| line = lines[i] | ||
|
|
||
| # 检测plugin开始 | ||
| if '<plugin>' in line and 'maven-compiler-plugin' in '\n'.join(lines[max(0, i-3):i+3]): | ||
| # 向前查找groupId和artifactId | ||
| if i > 0 and 'maven-compiler-plugin' in lines[i-1]: | ||
| plugin_start = len(new_lines) | ||
| indent = line[:len(line) - len(line.lstrip())] | ||
| in_plugin = True | ||
| new_lines.append(line) | ||
| i += 1 | ||
| continue | ||
|
|
||
| # 如果在plugin块中,检测groovy-eclipse-compiler | ||
| if in_plugin: | ||
| if '<compilerId>groovy-eclipse-compiler</compilerId>' in line: | ||
| # 找到了,需要替换整个plugin块 | ||
| # 回退到plugin开始位置 | ||
| new_lines = new_lines[:plugin_start] | ||
| # 添加新的标准配置 | ||
| version_line = None | ||
| for j in range(plugin_start, i): | ||
| if '<version>' in lines[j] and '</version>' in lines[j]: | ||
| version_line = lines[j] | ||
| break | ||
|
|
||
| version = '${project.compiler.version}' | ||
| if version_line: | ||
| version_match = re.search(r'<version>([^<]+)</version>', version_line) | ||
| if version_match: | ||
| version = version_match.group(1).strip() | ||
|
|
||
| new_lines.append(f'{indent}<plugin>') | ||
| new_lines.append(f'{indent} <groupId>org.apache.maven.plugins</groupId>') | ||
| new_lines.append(f'{indent} <artifactId>maven-compiler-plugin</artifactId>') | ||
| new_lines.append(f'{indent} <version>{version}</version>') | ||
| new_lines.append(f'{indent} <configuration>') | ||
| new_lines.append(f'{indent} <source>${{project.java.version}}</source>') | ||
| new_lines.append(f'{indent} <target>${{project.java.version}}</target>') | ||
| new_lines.append(f'{indent} <debug>true</debug>') | ||
| new_lines.append(f'{indent} <parameters>true</parameters>') | ||
| new_lines.append(f'{indent} </configuration>') | ||
| new_lines.append(f'{indent}</plugin>') | ||
|
|
||
| # 跳过到</plugin> | ||
| while i < len(lines) and '</plugin>' not in lines[i]: | ||
| i += 1 | ||
| if i < len(lines): | ||
| i += 1 # 跳过</plugin> | ||
| in_plugin = False | ||
| continue | ||
| elif '</plugin>' in line: | ||
| in_plugin = False | ||
| new_lines.append(line) | ||
| i += 1 | ||
| continue | ||
|
|
||
| new_lines.append(line) | ||
| i += 1 | ||
|
|
||
| new_content = '\n'.join(new_lines) | ||
|
|
||
| # 如果内容有变化,写入文件 | ||
| if new_content != content: | ||
| with open(file_path, 'w', encoding='utf-8') as f: | ||
| f.write(new_content) | ||
| print(" ✅ 修复完成") | ||
| sys.exit(0) | ||
| else: | ||
| print(" ⚠️ 未找到需要替换的内容(可能已修复或格式不同)") | ||
| sys.exit(1) | ||
|
|
||
| PYTHON_SCRIPT | ||
|
|
||
| if [ $? -eq 0 ]; then | ||
| FIXED=$((FIXED + 1)) | ||
| echo " ✅ 修复成功" | ||
| else | ||
| echo " ⚠️ 修复失败或无需修复,请手动检查" | ||
| SKIPPED=$((SKIPPED + 1)) | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n build/fix-groovy-compiler.sh | head -100 | tail -20Repository: MatheMatrix/zstack
Length of output: 592
🏁 Script executed:
wc -l build/fix-groovy-compiler.shRepository: MatheMatrix/zstack
Length of output: 94
🏁 Script executed:
sed -n '90,110p' build/fix-groovy-compiler.shRepository: MatheMatrix/zstack
Length of output: 635
🏁 Script executed:
rg '使用|修复|错误|检测|匹配' build/fix-groovy-compiler.sh -cRepository: MatheMatrix/zstack
Length of output: 64
🏁 Script executed:
sed -n '1,30p' build/fix-groovy-compiler.shRepository: MatheMatrix/zstack
Length of output: 862
🏁 Script executed:
sed -n '200,266p' build/fix-groovy-compiler.shRepository: MatheMatrix/zstack
Length of output: 2478
🏁 Script executed:
sed -n '95,200p' build/fix-groovy-compiler.shRepository: MatheMatrix/zstack
Length of output: 3346
消除代码中的中文内容并改进 heredoc 处理方式
此脚本违反编码规范:代码、注释和错误消息中包含大量中文(第 2、3、12、15-17、85、95、263、265、267 行等),应使用正确的英文改写。
其次,第 96 行的未引号 heredoc 允许 shell 展开变量,虽然当前代码中的 ${project.java.version} 已通过 \$ 转义避免了问题,但使用带引号的 heredoc(<<'PYTHON_SCRIPT')并通过环境变量传递 $FILE 是更安全、更清晰的做法:
🔧 建议修复
- # 使用Python进行精确替换(因为sed处理多行和缩进比较复杂)
- python3 <<PYTHON_SCRIPT
+ # Use Python for precise replacement (sed is complex with multiline and indentation)
+ if FILE="$FILE" python3 <<'PYTHON_SCRIPT'
import re
import sys
+import os
@@
-file_path = "$FILE"
+file_path = os.environ["FILE"]
@@
-PYTHON_SCRIPT
-
- if [ $? -eq 0 ]; then
- FIXED=$((FIXED + 1))
- echo " ✅ 修复成功"
- else
- echo " ⚠️ 修复失败或无需修复,请手动检查"
- SKIPPED=$((SKIPPED + 1))
- fi
+PYTHON_SCRIPT
+ then
+ FIXED=$((FIXED + 1))
+ echo " ✅ Fix successful"
+ else
+ echo " ⚠️ Fix failed or no changes needed, please check manually"
+ SKIPPED=$((SKIPPED + 1))
+ fi同时,将整个脚本中的所有中文注释、输出消息和日志改为清晰的英文。
🧰 Tools
🪛 Shellcheck (0.11.0)
[error] 167-167: Parameter expansions can't start with {. Double check syntax.
(SC2296)
[error] 168-168: Parameter expansions can't start with {. Double check syntax.
(SC2296)
[warning] 212-212: project is referenced but not assigned.
(SC2154)
[error] 223-223: Parameter expansions can't start with {. Double check syntax.
(SC2296)
[error] 224-224: Parameter expansions can't start with {. Double check syntax.
(SC2296)
🤖 Prompt for AI Agents
In `@build/fix-groovy-compiler.sh` around lines 95 - 266, The script contains
Chinese text and uses an unquoted heredoc for the embedded Python block; replace
all Chinese comments and user-facing messages with English and switch the
heredoc to a single-quoted form (use <<'PYTHON_SCRIPT') so the shell will not
expand variables inside the block, and pass the FILE path into the Python script
via an exported environment variable (or as an argument) instead of relying on
unescaped expansions; update prints like "✅ 修复完成"/"⚠️ 未找到需要替换的内容" and shell
echoes "✅ 修复成功"/"⚠️ 修复失败或无需修复,请手动检查" to clear English equivalents, ensure the
Python logic (functions/variables: pattern, pattern2, replace_plugin,
lines/new_lines, version detection using version_line and version_match)
continues to work with the quoted heredoc and the existing escaped
${project.java.version} strings, and verify the script exits with the same
status behavior.
| #!/bin/bash | ||
| # Java 17 兼容性验证脚本 | ||
| # 用于验证所有依赖在Java 17下的兼容性 | ||
|
|
||
| set -e | ||
|
|
||
| echo "==========================================" | ||
| echo " Java 17 兼容性验证" | ||
| echo "==========================================" | ||
| echo "" | ||
|
|
||
| # 1. 检查Java版本 | ||
| echo "[1/6] 检查Java版本..." | ||
| JAVA_VERSION=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1) | ||
| if [ "$JAVA_VERSION" != "17" ]; then | ||
| echo "❌ 错误: 需要Java 17,当前版本: $JAVA_VERSION" | ||
| java -version | ||
| exit 1 | ||
| fi | ||
| echo "✓ Java版本: $(java -version 2>&1 | head -1)" | ||
| echo "" | ||
|
|
||
| # 2. 检查关键依赖版本 | ||
| echo "[2/6] 检查关键依赖版本..." | ||
| echo "检查Spring Framework版本..." | ||
| SPRING_VERSION=$(mvn help:evaluate -Dexpression=spring.framework.version -q -DforceStdout 2>/dev/null || echo "unknown") | ||
| echo " Spring Framework: $SPRING_VERSION" | ||
| if [[ "$SPRING_VERSION" == "5.2"* ]]; then | ||
| echo " ⚠️ 警告: Spring 5.2.x 非官方支持Java 17,建议升级到5.3.x" | ||
| fi | ||
|
|
||
| echo "检查Hibernate版本..." | ||
| HIBERNATE_VERSION=$(mvn help:evaluate -Dexpression=hibernate.version -q -DforceStdout 2>/dev/null || echo "unknown") | ||
| echo " Hibernate: $HIBERNATE_VERSION" | ||
|
|
||
| echo "检查AspectJ版本..." | ||
| ASPECTJ_VERSION=$(mvn help:evaluate -Dexpression=aspectj.version -q -DforceStdout 2>/dev/null || echo "unknown") | ||
| echo " AspectJ: $ASPECTJ_VERSION" | ||
|
|
||
| echo "检查Groovy版本..." | ||
| GROOVY_VERSION=$(mvn help:evaluate -Dexpression=groovy.version -q -DforceStdout 2>/dev/null || echo "unknown") | ||
| echo " Groovy: $GROOVY_VERSION" | ||
| echo "" | ||
|
|
||
| # 3. 编译测试(核心模块) | ||
| echo "[3/6] 编译核心模块 (core, header, utils)..." | ||
| if mvn clean compile -pl core,header,utils -DskipTests -q; then | ||
| echo "✓ 核心模块编译成功" | ||
| else | ||
| echo "❌ 错误: 核心模块编译失败" | ||
| exit 1 | ||
| fi | ||
| echo "" | ||
|
|
||
| # 4. 编译测试(所有模块) | ||
| echo "[4/6] 编译所有模块..." | ||
| if mvn clean compile -DskipTests -q; then | ||
| echo "✓ 全量编译成功" | ||
| else | ||
| echo "❌ 错误: 全量编译失败" | ||
| exit 1 | ||
| fi | ||
| echo "" | ||
|
|
||
| # 5. 单元测试(工具类) | ||
| echo "[5/6] 运行单元测试 (utils, abstraction)..." | ||
| if mvn test -pl utils,abstraction -Djacoco.skip=true -q 2>&1 | tee /tmp/java17-test.log; then | ||
| echo "✓ 单元测试通过" | ||
| else | ||
| TEST_FAILED=$(grep -c "FAILURE\|ERROR" /tmp/java17-test.log || echo "0") | ||
| if [ "$TEST_FAILED" -gt 0 ]; then | ||
| echo "⚠️ 警告: 部分单元测试失败,请检查日志" | ||
| else | ||
| echo "✓ 单元测试完成" | ||
| fi | ||
| fi | ||
| echo "" | ||
|
|
||
| # 6. 依赖兼容性检查 | ||
| echo "[6/6] 检查依赖树(Spring/Hibernate相关)..." | ||
| echo "Spring相关依赖:" | ||
| mvn dependency:tree -Dincludes=org.springframework:* -q 2>/dev/null | grep -E "spring" | head -10 || echo " 无Spring依赖" | ||
| echo "" | ||
| echo "Hibernate相关依赖:" | ||
| mvn dependency:tree -Dincludes=org.hibernate:* -q 2>/dev/null | grep -E "hibernate" | head -10 || echo " 无Hibernate依赖" | ||
| echo "" | ||
|
|
||
| echo "==========================================" | ||
| echo " 验证完成" | ||
| echo "==========================================" | ||
| echo "" | ||
| echo "建议:" | ||
| if [[ "$SPRING_VERSION" == "5.2"* ]]; then | ||
| echo " - 考虑升级Spring Framework到5.3.23以获得官方Java 17支持" | ||
| fi | ||
| echo " - 运行完整集成测试: mvn test -pl test -Dtest=SomeBasicCase" | ||
| echo " - 检查运行时兼容性: 启动应用并测试核心功能" | ||
| echo "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
违反编码规范:脚本中包含大量中文文本
根据编码规范要求,代码中不应包含中文,包括报错、注释等都应使用正确的英文。此脚本中的注释和输出消息全部使用了中文,需要改为英文。
🛠️ 建议的修复方案(部分示例)
#!/bin/bash
-# Java 17 兼容性验证脚本
-# 用于验证所有依赖在Java 17下的兼容性
+# Java 17 Compatibility Verification Script
+# Verifies compatibility of all dependencies with Java 17
set -e
echo "=========================================="
-echo " Java 17 兼容性验证"
+echo " Java 17 Compatibility Verification"
echo "=========================================="
echo ""
-# 1. 检查Java版本
-echo "[1/6] 检查Java版本..."
+# 1. Check Java version
+echo "[1/6] Checking Java version..."
JAVA_VERSION=$(java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1)
if [ "$JAVA_VERSION" != "17" ]; then
- echo "❌ 错误: 需要Java 17,当前版本: $JAVA_VERSION"
+ echo "❌ Error: Java 17 required, current version: $JAVA_VERSION"
java -version
exit 1
fi
-echo "✓ Java版本: $(java -version 2>&1 | head -1)"
+echo "✓ Java version: $(java -version 2>&1 | head -1)"
echo ""
-# 2. 检查关键依赖版本
-echo "[2/6] 检查关键依赖版本..."
-echo "检查Spring Framework版本..."
+# 2. Check critical dependency versions
+echo "[2/6] Checking critical dependency versions..."
+echo "Checking Spring Framework version..."
SPRING_VERSION=$(mvn help:evaluate -Dexpression=spring.framework.version -q -DforceStdout 2>/dev/null || echo "unknown")
echo " Spring Framework: $SPRING_VERSION"
if [[ "$SPRING_VERSION" == "5.2"* ]]; then
- echo " ⚠️ 警告: Spring 5.2.x 非官方支持Java 17,建议升级到5.3.x"
+ echo " ⚠️ Warning: Spring 5.2.x does not officially support Java 17, recommend upgrading to 5.3.x"
fi其余中文文本同样需要翻译为英文。
根据编码规范:"代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写"。
🤖 Prompt for AI Agents
In `@build/verify-java17.sh` around lines 1 - 98, The script contains Chinese
comments and output strings; replace all Chinese text with clear English
equivalents (e.g., change header echoes, section markers "[1/6]".."[6/6]",
comment lines, error messages and suggestions) while preserving logic and
variable names like JAVA_VERSION, SPRING_VERSION, HIBERNATE_VERSION,
ASPECTJ_VERSION, GROOVY_VERSION and temp log /tmp/java17-test.log; update
messages for success/failure (e.g., "❌ 错误: 需要Java 17..." → "ERROR: Java 17 is
required, current version: ...", "✓ 核心模块编译成功" → "OK: core modules compiled") and
translate all other echoed guidance and comments to idiomatic, correctly spelled
English.
| javaOptitons="$jvmOptions -Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" | ||
| java $javaOptions -cp $classPath org.zstack.portal.main.Main "$@" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n build/zstack-debug | sed -n '25,35p'Repository: MatheMatrix/zstack
Length of output: 539
修正 javaOptions 变量拼写错误,避免 JVM 参数丢失
Line 29 定义了 javaOptitons(拼写错误),但 Line 30 使用 javaOptions,导致该变量未定义,JVM 参数无法传递。
🔧 建议修复
- javaOptitons="$jvmOptions -Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
- java $javaOptions -cp $classPath org.zstack.portal.main.Main "$@"
+ javaOptions="$jvmOptions -Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"
+ java $javaOptions -cp "$classPath" org.zstack.portal.main.Main "$@"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| javaOptitons="$jvmOptions -Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" | |
| java $javaOptions -cp $classPath org.zstack.portal.main.Main "$@" | |
| javaOptions="$jvmOptions -Xdebug -Xms256m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y" | |
| java $javaOptions -cp "$classPath" org.zstack.portal.main.Main "$@" |
🤖 Prompt for AI Agents
In `@build/zstack-debug` around lines 29 - 30, The script defines the JVM options
into a misspelled variable javaOptitons but then invokes java using javaOptions,
so the JVM flags are never passed; fix by correcting the variable name so both
places use the same identifier (either rename javaOptitons to javaOptions where
it’s defined or change the invocation to use javaOptitons) and ensure the value
includes the intended flags (-Xdebug -Xms256m -Xmx512m
-XX:+HeapDumpOnOutOfMemoryError
-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y) so the JVM
receives the parameters.
| # Java 17 模块系统配置 | ||
| # 开放反射访问(226处setAccessible需要) | ||
| --add-opens java.base/java.lang=ALL-UNNAMED | ||
| --add-opens java.base/java.lang.reflect=ALL-UNNAMED | ||
| --add-opens java.base/java.util=ALL-UNNAMED | ||
| --add-opens java.base/java.util.concurrent=ALL-UNNAMED | ||
| --add-opens java.base/java.io=ALL-UNNAMED | ||
| --add-opens java.base/java.net=ALL-UNNAMED | ||
|
|
||
| # 导出内部API(sun.misc.Signal需要) | ||
| --add-exports java.base/sun.misc=ALL-UNNAMED | ||
| --add-exports java.base/sun.security.ssl=ALL-UNNAMED | ||
|
|
||
| # Hibernate需要 | ||
| --add-opens java.base/java.time=ALL-UNNAMED | ||
|
|
||
| # AspectJ需要 | ||
| --add-opens java.base/java.lang.invoke=ALL-UNNAMED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
配置文件注释请改为英文
当前注释为中文,请统一为英文。
As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🤖 Prompt for AI Agents
In `@conf/jvm-options-java17.conf` around lines 1 - 18, Replace all Chinese
comments in this JVM options file with clear English comments: change the file
header comment to "Java 17 module system configuration", the reflective-access
note "开放反射访问(226处setAccessible需要)" to "Open reflective access (required for
setAccessible usages)", the internal-API export note
"导出内部API(sun.misc.Signal需要)" to "Export internal APIs (required for
sun.misc.Signal)", the Hibernate note "Hibernate需要" to "Required by Hibernate",
and the AspectJ note "AspectJ需要" to "Required by AspectJ"; keep the option lines
(--add-opens, --add-exports, --add-opens java.base/java.time, --add-opens
java.base/java.lang.invoke) unchanged.
| # ZStack 后端架构索引 | ||
|
|
||
| > 本文档描述 ZStack IaaS 云计算平台后端的核心架构设计、组件机制和扩展方式。 | ||
|
|
||
| ## 目录 | ||
|
|
||
| - [一、架构概览](#一架构概览) | ||
| - [二、核心框架层](#二核心框架层) | ||
| - [2.1 消息总线 (CloudBus)](#21-消息总线-cloudbus) | ||
| - [2.2 依赖注入与组件管理](#22-依赖注入与组件管理) | ||
| - [2.3 数据库访问层 (DatabaseFacade)](#23-数据库访问层-databasefacade) | ||
| - [2.4 异步编程模型 (ThreadFacade)](#24-异步编程模型-threadfacade) | ||
| - [2.5 错误处理机制 (ErrorFacade)](#25-错误处理机制-errorfacade) | ||
| - [三、API 消息设计](#三api-消息设计) | ||
| - [3.1 消息类型层次](#31-消息类型层次) | ||
| - [3.2 数据模型架构](#32-数据模型架构) | ||
| - [3.3 关键注解](#33-关键注解) | ||
| - [四、REST API 层](#四rest-api-层) | ||
| - [4.1 核心组件](#41-核心组件) | ||
| - [4.2 请求处理流程](#42-请求处理流程) | ||
| - [4.3 异步 API 机制](#43-异步-api-机制) | ||
| - [4.4 限流机制](#44-限流机制) | ||
| - [五、工作流引擎 (FlowChain)](#五工作流引擎-flowchain) | ||
| - [5.1 工作流类型](#51-工作流类型) | ||
| - [5.2 Flow 接口](#52-flow-接口) | ||
| - [5.3 回滚机制](#53-回滚机制) | ||
| - [六、插件扩展系统](#六插件扩展系统) | ||
| - [6.1 插件类型分类](#61-插件类型分类) | ||
| - [6.2 插件注册方式](#62-插件注册方式) | ||
| - [6.3 扩展点类型](#63-扩展点类型) | ||
| - [七、配置管理系统](#七配置管理系统) | ||
| - [7.1 GlobalConfig (全局配置)](#71-globalconfig-全局配置) | ||
| - [7.2 ResourceConfig (资源配置)](#72-resourceconfig-资源配置) | ||
| - [八、启动流程](#八启动流程) | ||
| - [8.1 启动入口](#81-启动入口) | ||
| - [8.2 管理节点启动步骤](#82-管理节点启动步骤) | ||
| - [8.3 数据库 Schema 管理](#83-数据库-schema-管理) | ||
| - [九、测试框架](#九测试框架) | ||
| - [9.1 测试框架结构](#91-测试框架结构) | ||
| - [9.2 模拟器机制](#92-模拟器机制) | ||
| - [9.3 环境定义 DSL](#93-环境定义-dsl) | ||
| - [十、架构特性总结](#十架构特性总结) | ||
|
|
||
| --- | ||
|
|
||
| ## 一、架构概览 | ||
|
|
||
| ZStack 是一个企业级开源 IaaS 云计算平台,采用 **Java + Spring + JPA/Hibernate** 技术栈,以**消息总线**为核心构建分布式、可扩展的微服务架构。 | ||
|
|
||
| ### 核心设计理念 | ||
|
|
||
| | 理念 | 说明 | | ||
| |------|------| | ||
| | **全异步架构** | 所有操作通过消息总线异步执行,提升系统吞吐量 | | ||
| | **插件化扩展** | 通过扩展点机制实现模块解耦,便于新功能接入 | | ||
| | **声明式 API** | 注解驱动的 REST API 设计,简化开发 | | ||
| | **统一错误处理** | AOP + 错误码体系,保证系统稳定性 | | ||
|
|
||
| ### 核心技术栈 | ||
|
|
||
| | 层次 | 技术 | | ||
| |------|------| | ||
| | 依赖注入 | Spring Framework | | ||
| | ORM | JPA / Hibernate | | ||
| | AOP | AspectJ | | ||
| | 消息传输 | HTTP / RabbitMQ | | ||
| | 测试框架 | JUnit + Groovy DSL | | ||
| | 数据库迁移 | Flyway | | ||
| | 连接池 | C3P0 | | ||
|
|
||
| ### 项目模块结构 | ||
|
|
||
| ``` | ||
| zstack/ | ||
| ├── core/ # 核心框架(消息总线、数据库、线程、错误处理) | ||
| ├── header/ # API 消息定义、VO/Inventory、常量枚举 | ||
| ├── rest/ # REST API 服务器 | ||
| ├── portal/ # 管理节点启动入口 | ||
| ├── configuration/ # 配置管理 | ||
| ├── resourceconfig/ # 资源级配置 | ||
| ├── compute/ # 计算资源管理 | ||
| ├── storage/ # 存储资源管理 | ||
| ├── network/ # 网络资源管理 | ||
| ├── identity/ # 身份认证 | ||
| ├── image/ # 镜像管理 | ||
| ├── plugin/ # 插件模块(KVM、Ceph、虚拟路由器等) | ||
| ├── test/ # 集成测试 | ||
| ├── testlib/ # 测试框架库 | ||
| ├── simulator/ # 模拟器 | ||
| └── conf/ # 配置文件和数据库 Schema | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 二、核心框架层 | ||
|
|
||
| 核心框架位于 `core/src/main/java/org/zstack/core/` 目录。 | ||
|
|
||
| ### 2.1 消息总线 (CloudBus) | ||
|
|
||
| 消息总线是 ZStack 架构的核心,负责服务间通信。 | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类/接口 | 路径 | 说明 | | ||
| |---------|------|------| | ||
| | `CloudBus` | `core/cloudbus/CloudBus.java` | 消息总线核心接口 | | ||
| | `CloudBusImpl3` | `core/cloudbus/CloudBusImpl3.java` | 当前实现(基于 HTTP) | | ||
| | `CloudBusImpl2` | `core/cloudbus/CloudBusImpl2.java` | 旧实现(基于 RabbitMQ) | | ||
|
|
||
| #### 消息类型层次 | ||
|
|
||
| ``` | ||
| Message (基础消息) | ||
| └── NeedReplyMessage (需要回复的消息) | ||
| └── APIMessage (API 消息) | ||
| ├── APICreateMessage (创建资源) | ||
| ├── APIGetMessage (获取资源) | ||
| └── APIQueryMessage (查询资源) | ||
|
|
||
| MessageReply (消息回复) | ||
| └── APIReply (API 回复) | ||
|
|
||
| Event (事件) | ||
| └── APIEvent (API 事件) | ||
| ``` | ||
|
|
||
| #### 核心功能 | ||
|
|
||
| | 方法 | 说明 | | ||
| |------|------| | ||
| | `send(msg, callback)` | 异步发送消息,通过回调接收响应 | | ||
| | `call(msg)` | 同步调用,阻塞等待回复 | | ||
| | `route(msg)` | 根据 `serviceId` 路由消息到对应服务 | | ||
| | `publish(event)` | 发布事件给所有订阅者 | | ||
| | `registerService(service)` | 注册服务到消息总线 | | ||
|
|
||
| #### 使用示例 | ||
|
|
||
| ```java | ||
| // 异步发送 | ||
| bus.send(msg, new CloudBusCallBack(completion) { | ||
| @Override | ||
| public void run(MessageReply reply) { | ||
| if (reply.isSuccess()) { | ||
| // 处理成功 | ||
| } else { | ||
| // 处理失败 | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| // 同步调用 | ||
| MessageReply reply = bus.call(msg); | ||
| ``` | ||
|
|
||
| ### 2.2 依赖注入与组件管理 | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类/接口 | 路径 | 说明 | | ||
| |---------|------|------| | ||
| | `ComponentLoader` | `core/componentloader/ComponentLoader.java` | 组件加载器接口 | | ||
| | `ComponentLoaderImpl` | `core/componentloader/ComponentLoaderImpl.java` | 基于 Spring 的实现 | | ||
| | `PluginRegistry` | `core/componentloader/PluginRegistry.java` | 插件注册表接口 | | ||
| | `PluginRegistryImpl` | `core/componentloader/PluginRegistryImpl.java` | 插件注册实现 | | ||
| | `Platform` | `core/Platform.java` | 平台入口(静态访问) | | ||
|
|
||
| #### 组件生命周期接口 | ||
|
|
||
| ```java | ||
| // 组件接口 - 定义生命周期 | ||
| public interface Component { | ||
| boolean start(); // 启动 | ||
| boolean stop(); // 停止 | ||
| } | ||
|
|
||
| // 服务接口 - 可处理消息 | ||
| public interface Service extends Component { | ||
| void handleMessage(Message msg); // 处理消息 | ||
| String getId(); // 服务 ID | ||
| int getSyncLevel(); // 同步级别 | ||
| List<String> getAliasIds(); // 别名 | ||
| } | ||
| ``` | ||
|
|
||
| #### 获取组件 | ||
|
|
||
| ```java | ||
| // 通过 Platform 静态方法获取 | ||
| DatabaseFacade dbf = Platform.getComponentLoader().getComponent(DatabaseFacade.class); | ||
|
|
||
| // 或使用 Spring 注入 | ||
| @Autowired | ||
| private DatabaseFacade dbf; | ||
| ``` | ||
|
|
||
| ### 2.3 数据库访问层 (DatabaseFacade) | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类/接口 | 路径 | 说明 | | ||
| |---------|------|------| | ||
| | `DatabaseFacade` | `core/db/DatabaseFacade.java` | 数据库门面接口 | | ||
| | `DatabaseFacadeImpl` | `core/db/DatabaseFacadeImpl.java` | JPA/Hibernate 实现 | | ||
| | `SQLBatch` | `core/db/SQLBatch.java` | SQL 批处理抽象类 | | ||
| | `SimpleQuery` | `core/db/SimpleQuery.java` | 查询构建器 | | ||
| | `SQL` | `core/db/SQL.java` | SQL 工具类 | | ||
|
|
||
| #### 核心功能 | ||
|
|
||
| | 方法 | 说明 | | ||
| |------|------| | ||
| | `persist(entity)` | 持久化实体 | | ||
| | `update(entity)` | 更新实体 | | ||
| | `remove(entity)` | 删除实体(支持软删除) | | ||
| | `findByUuid(uuid, class)` | 按 UUID 查找 | | ||
| | `createQuery(class)` | 创建查询 | | ||
| | `eoCleanup(class)` | 清理软删除的实体对象 | | ||
|
|
||
| #### 软删除机制 | ||
|
|
||
| ```java | ||
| // VO 定义时使用 @EO 注解指定软删除实体 | ||
| @Entity | ||
| @Table | ||
| @EO(EOClazz = VmInstanceEO.class) | ||
| public class VmInstanceVO extends VmInstanceAO { | ||
| // ... | ||
| } | ||
|
|
||
| // 软删除级联 | ||
| @Entity | ||
| @SoftDeletionCascades({ | ||
| @SoftDeletionCascade(parent = VmInstanceVO.class, joinColumn = "vmInstanceUuid") | ||
| }) | ||
| public class VmNicVO extends VmNicAO { | ||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| #### 死锁处理 | ||
|
|
||
| ```java | ||
| // 使用 @DeadlockAutoRestart 自动重试 | ||
| @DeadlockAutoRestart | ||
| public void updateResource() { | ||
| // 可能发生死锁的操作 | ||
| } | ||
| ``` | ||
|
|
||
| ### 2.4 异步编程模型 (ThreadFacade) | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类/接口 | 路径 | 说明 | | ||
| |---------|------|------| | ||
| | `ThreadFacade` | `core/thread/ThreadFacade.java` | 线程管理门面接口 | | ||
| | `ThreadFacadeImpl` | `core/thread/ThreadFacadeImpl.java` | 线程池实现 | | ||
| | `Completion` | `header/core/Completion.java` | 无返回值回调 | | ||
| | `ReturnValueCompletion` | `header/core/ReturnValueCompletion.java` | 有返回值回调 | | ||
| | `NoErrorCompletion` | `header/core/NoErrorCompletion.java` | 无错误回调 | | ||
|
|
||
| #### 回调接口层次 | ||
|
|
||
| ``` | ||
| AbstractCompletion (抽象基类) | ||
| ├── Completion (无返回值回调) | ||
| │ ├── success() | ||
| │ └── fail(ErrorCode) | ||
| │ | ||
| ├── ReturnValueCompletion<T> (有返回值回调) | ||
| │ ├── success(T returnValue) | ||
| │ └── fail(ErrorCode) | ||
| │ | ||
| └── NoErrorCompletion (无错误回调) | ||
| └── done() | ||
| ``` | ||
|
|
||
| #### 异步执行注解 | ||
|
|
||
| | 注解 | 说明 | | ||
| |------|------| | ||
| | `@AsyncThread` | 异步执行方法 | | ||
| | `@SyncThread` | 同步执行(带同步级别) | | ||
| | `@ScheduledThread` | 定时执行 | | ||
|
|
||
| #### 同步控制机制 | ||
|
|
||
| ```java | ||
| // SyncTask 接口 - 支持同步级别 | ||
| public interface SyncTask<T> extends Task<T> { | ||
| String getSyncSignature(); // 同步签名,相同签名的任务串行执行 | ||
| int getSyncLevel(); // 同步级别 | ||
| } | ||
|
|
||
| // 使用示例 | ||
| thdf.syncSubmit(new SyncTask<Void>() { | ||
| @Override | ||
| public String getSyncSignature() { | ||
| return "host-" + hostUuid; // 同一主机的操作串行执行 | ||
| } | ||
|
|
||
| @Override | ||
| public Void call() throws Exception { | ||
| // 执行操作 | ||
| return null; | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| #### SingleFlight 模式 | ||
|
|
||
| ```java | ||
| // 相同 key 的请求只执行一次 | ||
| thdf.singleFlightSubmit(new SingleFlightTask(completion) { | ||
| @Override | ||
| public String getSingleFlightKey() { | ||
| return "refresh-" + resourceUuid; | ||
| } | ||
|
|
||
| @Override | ||
| public void run(SingleFlightCompletion completion) { | ||
| // 执行操作 | ||
| completion.success(result); | ||
| } | ||
| }); | ||
| ``` | ||
|
|
||
| ### 2.5 错误处理机制 (ErrorFacade) | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类/接口 | 路径 | 说明 | | ||
| |---------|------|------| | ||
| | `ErrorFacade` | `core/errorcode/ErrorFacade.java` | 错误处理门面接口 | | ||
| | `ErrorFacadeImpl` | `core/errorcode/ErrorFacadeImpl.java` | 错误处理实现 | | ||
| | `ErrorCode` | `header/errorcode/ErrorCode.java` | 错误码类 | | ||
| | `OperationFailureException` | `header/exception/OperationFailureException.java` | 操作失败异常 | | ||
|
|
||
| #### AOP 异常处理注解 | ||
|
|
||
| | 注解 | 切面 | 说明 | | ||
| |------|------|------| | ||
| | `@ExceptionSafe` | `ExceptionSafeAspect.aj` | 自动捕获异常 | | ||
| | `@MessageSafe` | `MessageSafeAspect.aj` | 消息处理异常自动回复 | | ||
|
|
||
| #### 错误码定义 | ||
|
|
||
| ```xml | ||
| <!-- XML 定义错误码 --> | ||
| <error> | ||
| <code>SYS.1001</code> | ||
| <description>Internal error</description> | ||
| </error> | ||
| ``` | ||
|
|
||
| #### 异常处理流程 | ||
|
|
||
| ``` | ||
| 方法抛出异常 | ||
| ↓ | ||
| AOP 拦截 (ExceptionSafeAspect / MessageSafeAspect) | ||
| ↓ | ||
| 转换为 ErrorCode | ||
| ↓ | ||
| 通过 Completion.fail(ErrorCode) 回调 | ||
| 或 | ||
| 通过 bus.replyErrorByMessageType() 回复消息 | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 三、API 消息设计 | ||
|
|
||
| API 消息定义位于 `header/src/main/java/org/zstack/header/` 目录。 | ||
|
|
||
| ### 3.1 消息类型层次 | ||
|
|
||
| | 类型 | 命名模式 | 基类 | 用途 | | ||
| |------|---------|------|------| | ||
| | 请求消息 | `API*Msg` | `APIMessage` | 客户端请求 | | ||
| | 异步事件 | `API*Event` | `APIEvent` | 异步操作结果通知 | | ||
| | 同步回复 | `API*Reply` | `APIReply` | 同步查询结果 | | ||
|
|
||
| #### 消息流模式 | ||
|
|
||
| ``` | ||
| 同步 API: APIMessage → CloudBus.call() → APIReply | ||
| 异步 API: APIMessage → CloudBus.send() → APIEvent (通过回调) | ||
|
|
||
| 资源操作模式: | ||
| - Create: APICreateXxxMsg → APICreateXxxEvent | ||
| - Update: APIUpdateXxxMsg → APIUpdateXxxEvent | ||
| - Delete: APIDeleteXxxMsg → APIDeleteXxxEvent | ||
| - Query: APIQueryXxxMsg → APIQueryXxxReply | ||
| - Get: APIGetXxxMsg → APIGetXxxReply | ||
| ``` | ||
|
|
||
| ### 3.2 数据模型架构 | ||
|
|
||
| #### 层次结构 | ||
|
|
||
| ``` | ||
| AO (Abstract Object) - 定义字段 | ||
| └── VO (Value Object) - 数据库实体 | ||
| └── EO (Entity Object) - 软删除视图 | ||
|
|
||
| 数据流转: | ||
| VO (数据库实体) → Inventory (DTO) → API Response (REST 响应) | ||
| ``` | ||
|
|
||
| #### VO 定义示例 | ||
|
|
||
| ```java | ||
| @Entity | ||
| @Table | ||
| @EO(EOClazz = VmInstanceEO.class) | ||
| @BaseResource | ||
| @EntityGraph( | ||
| parents = { | ||
| @EntityGraph.Neighbour(type = ZoneVO.class, myField = "zoneUuid", targetField = "uuid"), | ||
| }, | ||
| friends = { | ||
| @EntityGraph.Neighbour(type = ImageVO.class, myField = "imageUuid", targetField = "uuid"), | ||
| } | ||
| ) | ||
| public class VmInstanceVO extends VmInstanceAO implements OwnedByAccount, ToInventory { | ||
| // 字段定义 | ||
| } | ||
| ``` | ||
|
|
||
| #### Inventory 定义示例 | ||
|
|
||
| ```java | ||
| @Inventory(mappingVOClass = VmInstanceVO.class) | ||
| @ExpandedQueries({ | ||
| @ExpandedQuery(expandedField = "zone", inventoryClass = ZoneInventory.class, foreignKey = "zoneUuid") | ||
| }) | ||
| public class VmInstanceInventory implements Serializable { | ||
|
|
||
| public static VmInstanceInventory valueOf(VmInstanceVO vo) { | ||
| return new VmInstanceInventory(vo); | ||
| } | ||
|
|
||
| public static List<VmInstanceInventory> valueOf(Collection<VmInstanceVO> vos) { | ||
| return vos.stream().map(VmInstanceInventory::valueOf).collect(Collectors.toList()); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 3.3 关键注解 | ||
|
|
||
| #### @RestRequest | ||
|
|
||
| ```java | ||
| @RestRequest( | ||
| path = "/vm-instances", | ||
| method = HttpMethod.POST, | ||
| responseClass = APICreateVmInstanceEvent.class, | ||
| parameterName = "params" | ||
| ) | ||
| public class APICreateVmInstanceMsg extends APICreateMessage { | ||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| #### @APIParam | ||
|
|
||
| ```java | ||
| @APIParam( | ||
| required = true, // 必填 | ||
| maxLength = 255, // 最大长度 | ||
| resourceType = ZoneVO.class, // 资源类型验证 | ||
| checkAccount = true, // 账户权限检查 | ||
| validValues = {"Enabled", "Disabled"} // 有效值 | ||
| ) | ||
| private String zoneUuid; | ||
| ``` | ||
|
|
||
| #### @RestResponse | ||
|
|
||
| ```java | ||
| @RestResponse(allTo = "inventory") // 所有字段映射到 inventory | ||
| public class APICreateVmInstanceEvent extends APIEvent { | ||
| private VmInstanceInventory inventory; | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 四、REST API 层 | ||
|
|
||
| REST API 实现位于 `rest/src/main/java/org/zstack/rest/` 目录。 | ||
|
|
||
| ### 4.1 核心组件 | ||
|
|
||
| | 类 | 说明 | | ||
| |----|------| | ||
| | `RestServer` | REST API 服务器核心实现 | | ||
| | `RestServerController` | Spring MVC 入口控制器 | | ||
| | `RateLimiter` | 限流器(Token Bucket 算法) | | ||
| | `AsyncRestApiStore` | 异步 API 存储接口 | | ||
| | `MysqlAsyncRestStore` | 异步 API 存储实现 | | ||
| | `RequestData` | 请求数据封装 | | ||
|
|
||
| ### 4.2 请求处理流程 | ||
|
|
||
| ``` | ||
| HTTP 请求 | ||
| ↓ | ||
| RestServerController (Spring MVC 入口) | ||
| ↓ | ||
| RestServer.handle() | ||
| ↓ | ||
| ┌─────────────────────────────────┐ | ||
| │ 1. 限流检查 (RateLimiter) │ | ||
| │ 2. 请求拦截器处理 │ | ||
| │ 3. 路径匹配 (AntPathMatcher) │ | ||
| │ 4. 认证处理 │ | ||
| │ ├─ OAuth: Authorization: OAuth <token> | ||
| │ └─ AccessKey: Authorization: ZStack <id>:<signature> | ||
| │ 5. 参数解析 │ | ||
| │ ├─ GET/DELETE: Query String │ | ||
| │ └─ POST/PUT: Request Body │ | ||
| │ 6. 构建 APIMessage │ | ||
| │ 7. 发送到 CloudBus │ | ||
| │ ├─ 同步调用 → 200 OK │ | ||
| │ └─ 异步调用 → 202 Accepted │ | ||
| └─────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| ### 4.3 异步 API 机制 | ||
|
|
||
| #### 工作流程 | ||
|
|
||
| ``` | ||
| 1. 请求提交 | ||
| POST /v1/vm-instances | ||
| → 保存到 AsyncRestVO (状态: processing) | ||
| → 发送消息到 CloudBus | ||
| → 返回 202 Accepted | ||
| → Location: /v1/api-jobs/{uuid} | ||
|
|
||
| 2. 状态查询 | ||
| GET /v1/api-jobs/{uuid} | ||
| → processing: 202 Accepted | ||
| → done + success: 200 OK | ||
| → done + failed: 503 Service Unavailable | ||
| → expired: 404 Not Found | ||
|
|
||
| 3. WebHook 回调 (可选) | ||
| 请求头: X-Web-Hook: <url> | ||
| 任务完成时自动 POST 结果到 WebHook URL | ||
| ``` | ||
|
|
||
| ### 4.4 限流机制 | ||
|
|
||
| 基于 Token Bucket 算法实现: | ||
|
|
||
| ```java | ||
| public class RateLimiter { | ||
| private final LoadingCache<String, TokenBucket> requestCache; | ||
| private final int maxRequestsPerMinute; | ||
|
|
||
| // 基于客户端 IP 限流 | ||
| public boolean isRateLimitExceeded(String clientIp) { | ||
| TokenBucket bucket = requestCache.get(clientIp); | ||
| return !bucket.tryConsume(); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 配置: | ||
| - 默认限制:12000 请求/分钟 | ||
| - 可通过 `RestGlobalProperty.REST_RATE_LIMITS` 配置 | ||
|
|
||
| --- | ||
|
|
||
| ## 五、工作流引擎 (FlowChain) | ||
|
|
||
| 工作流实现位于 `core/src/main/java/org/zstack/core/workflow/` 目录。 | ||
|
|
||
| ### 5.1 工作流类型 | ||
|
|
||
| | 类型 | 特点 | 适用场景 | | ||
| |------|------|---------| | ||
| | `SimpleFlowChain` | 内存执行,无持久化,性能好 | 简单业务流程 | | ||
| | `WorkFlowChain` | 数据库持久化,支持恢复 | 复杂流程,需状态恢复 | | ||
| | `AsyncWorkFlowChain` | 异步执行和回调 | 异步场景 | | ||
| | `ShareFlowChain` | 动态流程编排 | 运行时构建流程 | | ||
|
|
||
| ### 5.2 Flow 接口 | ||
|
|
||
| ```java | ||
| public interface Flow { | ||
| // 执行流程 | ||
| void run(FlowTrigger trigger, Map data); | ||
|
|
||
| // 回滚流程 | ||
| void rollback(FlowRollback trigger, Map data); | ||
|
|
||
| // 是否跳过(默认不跳过) | ||
| default boolean skip(Map data) { return false; } | ||
| } | ||
|
|
||
| public interface FlowTrigger { | ||
| void next(); // 继续下一个流程 | ||
| void fail(ErrorCode err); // 失败并触发回滚 | ||
| } | ||
|
|
||
| public interface FlowRollback { | ||
| void rollback(); // 继续回滚 | ||
| void skipRestRollbacks(); // 跳过剩余回滚 | ||
| } | ||
| ``` | ||
|
|
||
| #### 使用示例 | ||
|
|
||
| ```java | ||
| new SimpleFlowChain() | ||
| .setName("create-vm-flow") | ||
| .then(new Flow() { | ||
| @Override | ||
| public void run(FlowTrigger trigger, Map data) { | ||
| // 步骤 1:分配资源 | ||
| data.put("allocated", true); | ||
| trigger.next(); | ||
| } | ||
|
|
||
| @Override | ||
| public void rollback(FlowRollback trigger, Map data) { | ||
| // 回滚:释放资源 | ||
| releaseResource(); | ||
| trigger.rollback(); | ||
| } | ||
| }) | ||
| .then(new NoRollbackFlow() { | ||
| @Override | ||
| public void run(FlowTrigger trigger, Map data) { | ||
| // 步骤 2:启动 VM(无需回滚) | ||
| trigger.next(); | ||
| } | ||
| }) | ||
| .done(new FlowDoneHandler(completion) { | ||
| @Override | ||
| public void handle(Map data) { | ||
| // 完成处理 | ||
| completion.success(); | ||
| } | ||
| }) | ||
| .error(new FlowErrorHandler(completion) { | ||
| @Override | ||
| public void handle(ErrorCode err, Map data) { | ||
| // 错误处理 | ||
| completion.fail(err); | ||
| } | ||
| }) | ||
| .start(); | ||
| ``` | ||
|
|
||
| ### 5.3 回滚机制 | ||
|
|
||
| #### SimpleFlowChain 回滚 | ||
|
|
||
| - 使用栈结构(LIFO)实现逆序回滚 | ||
| - 调用 `trigger.next()` 时,当前 Flow 入栈 | ||
| - 调用 `trigger.fail(err)` 时,触发回滚 | ||
| - 支持 `skipRestRollbacks()` 跳过剩余回滚 | ||
|
|
||
| #### WorkFlowChain 回滚 | ||
|
|
||
| - 每个 Flow 状态持久化到 `WorkFlowVO` | ||
| - 支持 `carryOn(chainUuid)` 从断点继续执行 | ||
| - 自动判断继续策略:重启或继续回滚 | ||
|
|
||
| --- | ||
|
|
||
| ## 六、插件扩展系统 | ||
|
|
||
| 插件位于 `plugin/` 目录,每个插件是独立的 Maven 模块。 | ||
|
|
||
| ### 6.1 插件类型分类 | ||
|
|
||
| | 类型 | 插件 | 说明 | | ||
| |------|------|------| | ||
| | **Hypervisor** | `kvm` | KVM 虚拟化 | | ||
| | **Primary Storage** | `nfsPrimaryStorage`, `localstorage`, `ceph`, `sharedMountPointPrimaryStorage` | 主存储 | | ||
| | **Backup Storage** | `sftpBackupStorage` | 备份存储 | | ||
| | **Network Provider** | `virtualRouterProvider`, `flatNetworkProvider`, `sdnController` | 网络服务提供者 | | ||
| | **Network Service** | `securityGroup`, `portForwarding`, `loadBalancer`, `eip`, `vip` | 网络服务 | | ||
| | **认证/授权** | `ldap`, `loginPlugin`, `directory` | 身份认证 | | ||
|
|
||
| ### 6.2 插件注册方式 | ||
|
|
||
| #### XML 配置方式 | ||
|
|
||
| ```xml | ||
| <!-- 在 Spring XML 中注册插件 --> | ||
| <bean id="KVMHostFactory" class="org.zstack.kvm.KVMHostFactory"> | ||
| <zstack:plugin> | ||
| <zstack:extension interface="org.zstack.header.host.HypervisorFactory" /> | ||
| <zstack:extension interface="org.zstack.header.Component" /> | ||
| <zstack:extension interface="org.zstack.header.Service" /> | ||
| </zstack:plugin> | ||
| </bean> | ||
| ``` | ||
|
|
||
| #### 代码方式 (PluginDSL) | ||
|
|
||
| ```java | ||
| // 使用 PluginDSL 在代码中声明扩展 | ||
| PluginDSL.plugin("myPlugin") | ||
| .extension(SomeExtensionPoint.class, this) | ||
| .register(); | ||
| ``` | ||
|
|
||
| ### 6.3 扩展点类型 | ||
|
|
||
| #### Factory 模式 | ||
|
|
||
| ```java | ||
| // 定义工厂接口 | ||
| public interface HypervisorFactory { | ||
| HypervisorType getHypervisorType(); | ||
| Host createHost(HostVO vo); | ||
| } | ||
|
|
||
| // 实现工厂 | ||
| public class KVMHostFactory implements HypervisorFactory { | ||
| public static final HypervisorType hypervisorType = new HypervisorType("KVM"); | ||
|
|
||
| @Override | ||
| public HypervisorType getHypervisorType() { | ||
| return hypervisorType; | ||
| } | ||
| } | ||
|
|
||
| // 使用工厂 | ||
| List<HypervisorFactory> factories = pluginRgty.getExtensionList(HypervisorFactory.class); | ||
| ``` | ||
|
|
||
| #### Backend 模式 | ||
|
|
||
| ```java | ||
| // 定义后端接口 | ||
| public interface PortForwardingBackend { | ||
| NetworkServiceProviderType getProviderType(); | ||
| void applyPortForwardingRule(PortForwardingRuleInventory rule, Completion completion); | ||
| } | ||
|
|
||
| // 实现后端 | ||
| public class VirtualRouterPortForwardingBackend implements PortForwardingBackend { | ||
| @Override | ||
| public NetworkServiceProviderType getProviderType() { | ||
| return VirtualRouterConstant.VIRTUAL_ROUTER_PROVIDER_TYPE; | ||
| } | ||
| } | ||
|
|
||
| // 注册和使用 | ||
| Map<String, PortForwardingBackend> backends = new HashMap<>(); | ||
| for (PortForwardingBackend backend : pluginRgty.getExtensionList(PortForwardingBackend.class)) { | ||
| backends.put(backend.getProviderType().toString(), backend); | ||
| } | ||
| ``` | ||
|
|
||
| #### ExtensionPoint 回调模式 | ||
|
|
||
| ```java | ||
| // 定义扩展点接口 | ||
| public interface KVMStartVmExtensionPoint { | ||
| void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, StartVmCmd cmd); | ||
| void afterStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, StartVmCmd cmd); | ||
| } | ||
|
|
||
| // 实现扩展点 | ||
| public class CephPrimaryStorageFactory implements KVMStartVmExtensionPoint { | ||
| @Override | ||
| public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, StartVmCmd cmd) { | ||
| // 在 VM 启动前执行 Ceph 相关逻辑 | ||
| } | ||
| } | ||
|
|
||
| // 触发扩展点 | ||
| for (KVMStartVmExtensionPoint ext : pluginRgty.getExtensionList(KVMStartVmExtensionPoint.class)) { | ||
| ext.beforeStartVmOnKvm(host, spec, cmd); | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 七、配置管理系统 | ||
|
|
||
| ### 7.1 GlobalConfig (全局配置) | ||
|
|
||
| 位于 `core/src/main/java/org/zstack/core/config/` 目录。 | ||
|
|
||
| #### 核心类 | ||
|
|
||
| | 类 | 说明 | | ||
| |----|------| | ||
| | `GlobalConfig` | 配置项实体 | | ||
| | `GlobalConfigFacade` | 配置管理门面接口 | | ||
| | `GlobalConfigFacadeImpl` | 配置管理实现 | | ||
| | `GlobalConfigVO` | 配置数据库实体 | | ||
|
|
||
| #### 配置来源优先级 | ||
|
|
||
| ``` | ||
| 1. 数据库(运行时值) | ||
| 2. XML 配置文件(conf/globalConfig/*.xml) | ||
| 3. Java 注解(@GlobalConfigDef) | ||
| 4. 扩展点自动生成 | ||
| ``` | ||
|
|
||
| #### 定义方式 | ||
|
|
||
| **XML 方式**: | ||
| ```xml | ||
| <!-- conf/globalConfig/xxx.xml --> | ||
| <globalConfig> | ||
| <config> | ||
| <category>vm</category> | ||
| <name>vm.cleanTraffic</name> | ||
| <description>Whether to clean traffic when deleting VM</description> | ||
| <defaultValue>false</defaultValue> | ||
| <type>java.lang.Boolean</type> | ||
| </config> | ||
| </globalConfig> | ||
| ``` | ||
|
|
||
| **注解方式**: | ||
| ```java | ||
| @GlobalConfigDefinition | ||
| public class VmGlobalConfig { | ||
| public static final String CATEGORY = "vm"; | ||
|
|
||
| @GlobalConfigValidation(notNull = true) | ||
| public static GlobalConfig VM_CLEAN_TRAFFIC = new GlobalConfig(CATEGORY, "vm.cleanTraffic"); | ||
| } | ||
| ``` | ||
|
|
||
| #### 使用方式 | ||
|
|
||
| ```java | ||
| // 获取配置值 | ||
| boolean cleanTraffic = VmGlobalConfig.VM_CLEAN_TRAFFIC.value(Boolean.class); | ||
|
|
||
| // 监听配置变更 | ||
| VmGlobalConfig.VM_CLEAN_TRAFFIC.installUpdateExtension((oldValue, newValue) -> { | ||
| // 处理配置变更 | ||
| }); | ||
| ``` | ||
|
|
||
| ### 7.2 ResourceConfig (资源配置) | ||
|
|
||
| 位于 `resourceconfig/src/main/java/org/zstack/resourceconfig/` 目录。 | ||
|
|
||
| #### 与 GlobalConfig 的区别 | ||
|
|
||
| | 特性 | GlobalConfig | ResourceConfig | | ||
| |------|-------------|----------------| | ||
| | 作用域 | 全局共享 | 资源级独立设置 | | ||
| | 存储 | `GlobalConfigVO` | `ResourceConfigVO` | | ||
| | 查找顺序 | 直接返回全局值 | 资源 → 父资源 → GlobalConfig | | ||
|
|
||
| #### 绑定方式 | ||
|
|
||
| ```java | ||
| @GlobalConfigDefinition | ||
| public class VmGlobalConfig { | ||
| // 绑定到 VM 和 Cluster,支持多级继承 | ||
| @BindResourceConfig({VmInstanceVO.class, ClusterVO.class}) | ||
| public static GlobalConfig VM_VIDEO_TYPE = new GlobalConfig(CATEGORY, "videoType"); | ||
| } | ||
| ``` | ||
|
|
||
| #### 查找优先级 | ||
|
|
||
| ``` | ||
| 1. 资源自身配置(ResourceConfigVO 中 resourceUuid 匹配) | ||
| 2. 父资源配置(通过 DBGraph 查找父资源) | ||
| 3. GlobalConfig 默认值 | ||
| ``` | ||
|
|
||
| #### API 接口 | ||
|
|
||
| | API | 说明 | | ||
| |-----|------| | ||
| | `APIUpdateResourceConfigMsg` | 更新资源配置 | | ||
| | `APIDeleteResourceConfigMsg` | 删除资源配置 | | ||
| | `APIGetResourceConfigMsg` | 获取资源配置 | | ||
| | `APIGetResourceBindableConfigMsg` | 查询可绑定的配置 | | ||
|
|
||
| --- | ||
|
|
||
| ## 八、启动流程 | ||
|
|
||
| ### 8.1 启动入口 | ||
|
|
||
| ``` | ||
| Servlet 容器启动 | ||
| ↓ | ||
| BootstrapWebListener.contextInitialized() | ||
| → 触发 Platform 静态初始化 | ||
| ↓ | ||
| BootstrapContextLoaderListener.contextInitialized() | ||
| → 加载 Spring 上下文 (beanRefContext.xml → zstack.xml) | ||
| ↓ | ||
| ComponentLoaderWebListener.contextInitialized() | ||
| → Platform.createComponentLoaderFromWebApplicationContext() | ||
| → ManagementNodeManager.startNode() | ||
| ``` | ||
|
|
||
| ### 8.2 管理节点启动步骤 | ||
|
|
||
| `ManagementNodeManagerImpl.start()` 使用 FlowChain 编排启动步骤: | ||
|
|
||
| | 步骤 | 名称 | 说明 | | ||
| |------|------|------| | ||
| | 1 | `bootstrap-cloudbus` | CloudBus 初始化(已在 Platform 中完成) | | ||
| | 2 | `populate-components` | 收集所有 Component 和 Service | | ||
| | 3 | `register-node-on-cloudbus` | 注册管理节点服务到 CloudBus | | ||
| | 4 | `call-prepare-db-extension` | 准备数据库初始值 | | ||
| | 5 | `start-components` | 启动所有组件和服务 | | ||
| | 6 | `create-DB-record` | 创建/更新 ManagementNodeVO | | ||
| | 7 | `start-heartbeat` | 启动心跳机制 | | ||
| | 8 | `start-api-mediator` | 启动 API 中介器 | | ||
| | 9 | `set-node-to-running` | 设置节点状态为 RUNNING | | ||
| | 10 | `I-join` | 触发节点加入事件 | | ||
| | 11 | `node-is-ready` | 调用 ManagementNodeReadyExtensionPoint | | ||
| | 12 | `listen-node-life-cycle-events` | 监听节点生命周期事件 | | ||
| | 13 | `say-I-join` | 通知其他管理节点 | | ||
|
|
||
| ### 8.3 数据库 Schema 管理 | ||
|
|
||
| #### Flyway 迁移 | ||
|
|
||
| ```bash | ||
| # 部署脚本 (conf/deploydb.sh) | ||
| 1. 创建数据库(如果不存在) | ||
| 2. 复制 SQL 文件到 Flyway 目录 | ||
| - conf/db/V0.6__schema.sql (基础 schema) | ||
| - conf/db/upgrade/*.sql (升级脚本) | ||
| 3. Flyway clean (清理) | ||
| 4. Flyway baseline (创建 baseline) | ||
| 5. Flyway migrate (执行迁移,outOfOrder=true) | ||
| ``` | ||
|
|
||
| #### Schema 文件结构 | ||
|
|
||
| ``` | ||
| conf/db/ | ||
| ├── V0.6__schema.sql # 基础 schema | ||
| ├── upgrade/ | ||
| │ ├── V2.5.0__schema.sql # 升级脚本 | ||
| │ ├── V3.9.0__schema.sql | ||
| │ └── ... | ||
| ├── beforeMigrate.sql # 迁移前执行 | ||
| └── beforeValidate.sql # 验证前执行 | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 九、测试框架 | ||
|
|
||
| 测试框架位于 `test/` 和 `testlib/` 目录。 | ||
|
|
||
| ### 9.1 测试框架结构 | ||
|
|
||
| ```groovy | ||
| // 测试用例基类 | ||
| class ExampleCase extends SubCase { | ||
| EnvSpec env | ||
|
|
||
| @Override | ||
| void setup() { | ||
| // 配置 Spring,指定需要的服务模块 | ||
| spring { | ||
| sftpBackupStorage() | ||
| localStorage() | ||
| kvm() | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| void environment() { | ||
| // 定义测试环境 | ||
| env = env { | ||
| zone { | ||
| name = "zone1" | ||
| cluster { ... } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| void test() { | ||
| // 创建环境并执行测试 | ||
| env.create { | ||
| testMethod1() | ||
| testMethod2() | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| void clean() { | ||
| env.delete() | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### 生命周期 | ||
|
|
||
| ``` | ||
| setup() → 配置 Spring,指定模块 | ||
| environment() → 定义测试环境(不创建) | ||
| test() → env.create() 创建环境,执行测试 | ||
| clean() → 清理环境 | ||
| ``` | ||
|
|
||
| ### 9.2 模拟器机制 | ||
|
|
||
| 模拟器拦截 Agent HTTP 请求,返回模拟响应。 | ||
|
|
||
| ```groovy | ||
| class KVMSimulator implements Simulator { | ||
| @Override | ||
| void registerSimulators(EnvSpec spec) { | ||
| // 注册 KVM Agent 路径处理器 | ||
| spec.simulator(KVMConstant.KVM_HOST_CAPACITY_PATH) { HttpEntity<String> e, EnvSpec espec -> | ||
| def rsp = new KVMAgentCommands.HostCapacityResponse() | ||
| rsp.success = true | ||
| rsp.cpuNum = 8 | ||
| rsp.totalMemory = SizeUnit.GIGABYTE.toByte(32) | ||
| return rsp | ||
| } | ||
|
|
||
| spec.simulator(KVMConstant.KVM_START_VM_PATH) { HttpEntity<String> e -> | ||
| def cmd = JSONObjectUtil.toObject(e.body, KVMAgentCommands.StartVmCmd.class) | ||
| def rsp = new KVMAgentCommands.StartVmResponse() | ||
| rsp.success = true | ||
| return rsp | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### 处理器类型 | ||
|
|
||
| | 类型 | 说明 | | ||
| |------|------| | ||
| | `simulator(path, closure)` | 基础 HTTP 处理器 | | ||
| | `preSimulator(path, closure)` | 请求前处理器 | | ||
| | `afterSimulator(path, closure)` | 请求后处理器 | | ||
| | `hijackSimulator(path, closure)` | 最终拦截处理器 | | ||
|
|
||
| ### 9.3 环境定义 DSL | ||
|
|
||
| ```groovy | ||
| env = env { | ||
| zone { | ||
| name = "zone" | ||
| cluster { | ||
| name = "cluster" | ||
| kvmHost { | ||
| name = "host" | ||
| totalCpu = 8 | ||
| totalMem = SizeUnit.GIGABYTE.toByte(32) | ||
| } | ||
| } | ||
| instanceOffering { | ||
| name = "instanceOffering" | ||
| cpuNum = 2 | ||
| memorySize = SizeUnit.GIGABYTE.toByte(4) | ||
| } | ||
| diskOffering { | ||
| name = "diskOffering" | ||
| diskSize = SizeUnit.GIGABYTE.toByte(100) | ||
| } | ||
| sftpBackupStorage { | ||
| name = "bs" | ||
| url = "/tmp/bs" | ||
| } | ||
| nfsPrimaryStorage { | ||
| name = "ps" | ||
| url = "/tmp/ps" | ||
| } | ||
| l2NoVlanNetwork { | ||
| name = "l2" | ||
| l3Network { | ||
| name = "l3" | ||
| ip { | ||
| startIp = "192.168.0.2" | ||
| endIp = "192.168.0.254" | ||
| gateway = "192.168.0.1" | ||
| netmask = "255.255.255.0" | ||
| } | ||
| } | ||
| } | ||
| vm { | ||
| name = "vm" | ||
| useHost("host") | ||
| useL3Networks("l3") | ||
| useInstanceOffering("instanceOffering") | ||
| useImage("image") | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 十、架构特性总结 | ||
|
|
||
| ### 设计模式应用 | ||
|
|
||
| | 模式 | 应用场景 | | ||
| |------|---------| | ||
| | **门面模式** | `DatabaseFacade`, `ThreadFacade`, `ErrorFacade`, `GlobalConfigFacade` | | ||
| | **工厂模式** | `HypervisorFactory`, `PrimaryStorageFactory`, `BackupStorageFactory` | | ||
| | **观察者模式** | 事件订阅机制、配置变更监听 | | ||
| | **策略模式** | 插件扩展点、Backend 接口 | | ||
| | **模板方法** | `SQLBatch`, `AbstractService`, `Flow` | | ||
| | **责任链模式** | `FlowChain` 工作流 | | ||
| | **代理模式** | AOP 增强(AspectJ) | | ||
|
|
||
| ### 架构优势 | ||
|
|
||
| | 优势 | 说明 | | ||
| |------|------| | ||
| | **高度解耦** | 消息总线 + 插件系统实现模块解耦 | | ||
| | **可扩展性** | 扩展点机制便于新功能接入 | | ||
| | **异步优先** | 全异步架构提升系统吞吐量 | | ||
| | **容错性** | FlowChain 支持回滚和状态恢复 | | ||
| | **统一抽象** | 门面模式简化复杂性 | | ||
| | **测试友好** | 模拟器机制便于集成测试 | | ||
| | **配置灵活** | GlobalConfig + ResourceConfig 多级配置 | | ||
|
|
||
| ### 关键目录索引 | ||
|
|
||
| | 目录 | 内容 | | ||
| |------|------| | ||
| | `core/` | 核心框架(消息总线、数据库、线程、错误处理) | | ||
| | `header/` | API 消息定义、VO/Inventory、常量枚举 | | ||
| | `rest/` | REST API 服务器 | | ||
| | `portal/` | 管理节点启动入口 | | ||
| | `configuration/` | 配置管理 | | ||
| | `resourceconfig/` | 资源级配置 | | ||
| | `plugin/` | 插件模块 | | ||
| | `test/` | 集成测试 | | ||
| | `testlib/` | 测试框架库 | | ||
| | `conf/` | 配置文件和数据库 Schema | | ||
|
|
||
| --- | ||
|
|
||
| ## 附录:常用类速查 | ||
|
|
||
| ### 核心框架 | ||
|
|
||
| | 类 | 包路径 | 用途 | | ||
| |----|--------|------| | ||
| | `Platform` | `org.zstack.core` | 平台入口,静态访问组件 | | ||
| | `CloudBus` | `org.zstack.core.cloudbus` | 消息总线 | | ||
| | `DatabaseFacade` | `org.zstack.core.db` | 数据库访问 | | ||
| | `ThreadFacade` | `org.zstack.core.thread` | 线程管理 | | ||
| | `ErrorFacade` | `org.zstack.core.errorcode` | 错误处理 | | ||
| | `PluginRegistry` | `org.zstack.core.componentloader` | 插件注册 | | ||
| | `GlobalConfigFacade` | `org.zstack.core.config` | 全局配置 | | ||
|
|
||
| ### API 相关 | ||
|
|
||
| | 类 | 包路径 | 用途 | | ||
| |----|--------|------| | ||
| | `APIMessage` | `org.zstack.header.message` | API 消息基类 | | ||
| | `APIEvent` | `org.zstack.header.message` | API 事件基类 | | ||
| | `APIReply` | `org.zstack.header.message` | API 回复基类 | | ||
| | `RestServer` | `org.zstack.rest` | REST API 服务器 | | ||
|
|
||
| ### 工作流 | ||
|
|
||
| | 类 | 包路径 | 用途 | | ||
| |----|--------|------| | ||
| | `SimpleFlowChain` | `org.zstack.core.workflow` | 简单工作流 | | ||
| | `Flow` | `org.zstack.header.core.workflow` | 流程接口 | | ||
| | `FlowTrigger` | `org.zstack.header.core.workflow` | 流程触发器 | | ||
|
|
||
| ### 回调 | ||
|
|
||
| | 类 | 包路径 | 用途 | | ||
| |----|--------|------| | ||
| | `Completion` | `org.zstack.header.core` | 无返回值回调 | | ||
| | `ReturnValueCompletion` | `org.zstack.header.core` | 有返回值回调 | | ||
| | `NoErrorCompletion` | `org.zstack.header.core` | 无错误回调 | | ||
|
|
||
| --- | ||
|
|
||
| *文档版本: 1.0* | ||
| *最后更新: 2025-01* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
请确认文档语言是否符合仓库规范
当前文档为中文,若仓库要求英文文档,请补充英文版本或改为英文。
As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 53-53: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 53-53: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 53-53: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 53-53: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 62-62: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 62-62: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 62-62: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 62-62: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 73-73: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 106-106: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 106-106: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 106-106: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 106-106: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 106-106: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 106-106: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 113-113: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 131-131: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 131-131: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 131-131: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 131-131: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 162-162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 203-203: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 213-213: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 213-213: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 213-213: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 213-213: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 257-257: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 266-266: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 283-283: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 283-283: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 283-283: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 283-283: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 335-335: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 345-345: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 345-345: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 345-345: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 346-346: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 346-346: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 346-346: Table column style
Table pipe does not align with header for style "aligned"
(MD060, table-column-style)
[warning] 360-360: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 381-381: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 381-381: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 388-388: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 404-404: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 499-499: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 499-499: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 499-499: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 499-499: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 509-509: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 537-537: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 587-587: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 587-587: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 587-587: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 587-587: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 587-587: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 587-587: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 686-686: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 801-801: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 801-801: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 801-801: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 801-801: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 809-809: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 862-862: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 862-862: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 862-862: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 862-862: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 862-862: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 862-862: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 880-880: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 889-889: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 889-889: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 889-889: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 889-889: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 901-901: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 920-920: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 920-920: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 920-920: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 920-920: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 920-920: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 920-920: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 952-952: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 1015-1015: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 1052-1052: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1052-1052: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1052-1052: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1052-1052: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1119-1119: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1119-1119: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1119-1119: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1119-1119: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1131-1131: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1131-1131: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1131-1131: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1131-1131: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1143-1143: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1143-1143: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1143-1143: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1143-1143: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1162-1162: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1174-1174: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1183-1183: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 1191-1191: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
🤖 Prompt for AI Agents
In `@docs/ARCHITECTURE.md` around lines 1 - 1199, The document "ZStack 后端架构索引" is
in Chinese but the repo requires English-only content; update this
ARCHITECTURE.md by providing an English version (either replace the Chinese text
or add a full English translation alongside the Chinese), ensuring all headings,
descriptions, table entries, code comments/examples and appended notes (e.g.,
"文档版本", "最后更新") are converted to proper English, and keep structural identifiers
(like class/interface names: CloudBus, DatabaseFacade, ThreadFacade, FlowChain,
GlobalConfig, etc.) unchanged so readers can locate code references.
| # ZStack 构建加速指南 | ||
|
|
||
| ## 为什么 `-T 1C` 提升有限? | ||
|
|
||
| - **依赖链长**:header → core → plugin* → premium,大量模块串行,可并行的只有同一“层”的模块。 | ||
| - **单模块重**:mevoco、testlib-premium、hybrid、header 等单模块编译时间 30s~70s,并行只能缩短“层内”时间。 | ||
| - **内存压力**:并行会起多个 JVM(GMavenPlus/编译器),若总内存不足易触发 GC 或交换,反而变慢。 | ||
|
|
||
| --- | ||
|
|
||
| ## 推荐做法(按收益排序) | ||
|
|
||
| ### 1. 日常开发:不 clean,只编改动的模块(收益最大) | ||
|
|
||
| **从 zstack 根目录构建 premium 时,必须先激活 profile `-P premium`**(根 pom 默认模块列表里没有 premium,只有激活该 profile 后 reactor 才会包含 premium)。 | ||
|
|
||
| ```bash | ||
| # 只编 premium 整棵子工程(含其依赖:header、core、plugin 等) | ||
| # -Dmevoco.skip.obfuscate=true 避免 mvnd 下 exec 插件 NPE,见下文说明 | ||
| mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -pl premium -am | ||
|
|
||
| # 只编 premium 下某模块(如 mevoco)及其依赖 | ||
| mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -pl premium/mevoco -am | ||
|
|
||
| # 只编 premium 下某插件 | ||
| mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -pl premium/plugin-premium/某插件名 -am | ||
| ``` | ||
|
|
||
| 若**已进入 premium 目录**,则不需要 `-P premium`,直接: | ||
|
|
||
| ```bash | ||
| cd premium && mvnd install -DskipTests -Dmevoco.skip.obfuscate=true | ||
|
|
||
| # 只编 premium 内某模块 | ||
| cd premium && mvnd install -DskipTests -Dmevoco.skip.obfuscate=true -pl mevoco -am | ||
| ``` | ||
|
|
||
| 避免每次 `clean` 全量重编,可节省大半时间。 | ||
|
|
||
| ### 2. 使用 Maven Daemon(mvnd)— 二次及以后构建明显更快 | ||
|
|
||
| mvnd 保持 JVM 常驻,避免每次冷启动和重复加载类,对多模块项目通常有 **2~4 倍** 提升。 | ||
|
|
||
| ```bash | ||
| # macOS(mvnd 需通过官方 tap 安装,默认 brew 无此 formula) | ||
| brew install mvndaemon/homebrew-mvnd/mvnd | ||
|
|
||
| # 使用方式与 mvn 一致 | ||
| mvnd clean install -DskipTests | ||
| mvnd install -DskipTests -pl premium/mevoco -am | ||
| ``` | ||
|
|
||
| **使用 mvnd 构建含 premium 时**:exec-maven-plugin 在 mvnd 下会因 `MavenSession.getContainer()` 为 null 报错,需跳过 mevoco 的混淆步骤: | ||
|
|
||
| ```bash | ||
| mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true | ||
| ``` | ||
|
|
||
| 需要发布/混淆时用普通 Maven:`mvn install -DskipTests -P premium`(不加该参数)。 | ||
|
|
||
| 注意:首次运行仍会较慢,后续构建才会体现加速。 | ||
|
|
||
| **mvnd 内存与 Groovy 编译**:test-premium、test、testlib-premium 等模块大量使用 Groovy,gmavenplus 会在同一 JVM(mvnd daemon)里解析/编译,易占满堆或 Metaspace 导致无响应。已为 gmavenplus-plugin 开启 **`<fork>true</fork>`**:Groovy 编译在独立子进程中执行,完成后子进程退出释放内存,减轻 daemon 压力。根目录 `.mvn/jvm.config` 已为 mvnd daemon 配置: | ||
|
|
||
| - **堆**:`-Xmx10240m`(10GB),供 Groovy 源码与 stub 常驻 | ||
| - **Metaspace**:`-XX:MaxMetaspaceSize=2560m`(2.5GB),应对大量 Groovy/Java 类加载 | ||
| - **CodeCache**:`-XX:ReservedCodeCacheSize=512m`、`-XX:NonProfiledCodeHeapSize=240m`,避免 JIT 代码缓存满 | ||
| - **G1**:`-XX:+UseG1GC`、`-XX:+UseStringDeduplication` | ||
|
|
||
| 建议物理内存 ≥16GB 再跑 `mvnd install -DskipTests -P premium` 全量;否则可先用 `mvn` 或只编到 `test`(`-pl test -am`)。修改 `.mvn/jvm.config` 后必须重启 daemon 才生效: | ||
|
|
||
| ```bash | ||
| mvnd --stop | ||
| mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true | ||
| ``` | ||
|
|
||
| ### 3. 离线构建(依赖已齐全时) | ||
|
|
||
| ```bash | ||
| mvn install -DskipTests -o | ||
| ``` | ||
|
|
||
| 避免每次解析/检查远程仓库,可省数秒到数十秒。 | ||
|
|
||
| ### 4. 适当提高并行度(在内存充足时) | ||
|
|
||
| 若机器内存 ≥16GB,可尝试: | ||
|
|
||
| ```bash | ||
| # 最多 4 个线程,避免过多并行导致 OOM | ||
| mvn install -DskipTests -T 4 | ||
| ``` | ||
|
|
||
| 不建议在 8GB 或以下机器用 `-T 1C`,易与 `.mvn/jvm.config` 里的大堆一起导致交换。 | ||
|
|
||
| ### 5. 只编到某模块,不编完全部 | ||
|
|
||
| ```bash | ||
| # 只编到 build(含 header/core/plugin 等),不编 test/testlib/premium 测试相关 | ||
| mvn install -DskipTests -pl build -am | ||
|
|
||
| # 只编到 crypto,不编 testlib-premium / test-premium | ||
| mvn install -DskipTests -pl premium/crypto -am | ||
| ``` | ||
|
|
||
| 适合验证主链或某个子模块,跳过最耗时的 testlib-premium 等。 | ||
|
|
||
| ### 6. 关闭/缩短测试(已有 -DskipTests 时可略过) | ||
|
|
||
| 已使用 `-DskipTests` 时,测试已跳过。若某处仍会跑测试,可再加: | ||
|
|
||
| ```bash | ||
| -Dmaven.test.skip=true | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 建议的日常组合 | ||
|
|
||
| | 场景 | 命令示例 | | ||
| |------|----------| | ||
| | 从**根目录**只编 premium | `mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -pl premium -am` | | ||
| | 从**根目录**只编 mevoco | `mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -pl premium/mevoco -am` | | ||
| | 已 **cd premium**,只编某插件 | `mvnd install -DskipTests -Dmevoco.skip.obfuscate=true -pl plugin-premium/xxx -am` | | ||
| | 全量构建(含 premium,少用 clean) | `mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true` | | ||
| | 全量 + 并行(内存够) | `mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -T 4` | | ||
| | 依赖已全、不想连网 | `mvnd install -DskipTests -P premium -Dmevoco.skip.obfuscate=true -o` | | ||
|
|
||
| --- | ||
|
|
||
| ## 可选:为编译器开启增量(需各模块兼容) | ||
|
|
||
| 在根 `pom.xml` 的 `maven-compiler-plugin` 的 `pluginManagement` 里可统一开启: | ||
|
|
||
| ```xml | ||
| <configuration> | ||
| <useIncrementalCompilation>true</useIncrementalCompilation> | ||
| </configuration> | ||
| ``` | ||
|
|
||
| 部分老模块若出现“改完不重编”的异常,再对单模块关闭即可。当前项目未全局开启,可按需试验。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
请确认文档语言是否符合仓库规范
当前文档为中文,若仓库要求英文文档,请补充英文版本或改为英文。
As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🧰 Tools
🪛 LanguageTool
[uncategorized] ~94-~94: 您的意思是“易"于"”吗?
Context: ...ests -T 4 ``` 不建议在 8GB 或以下机器用 -T 1C,易与 `.mvn/jvm.config` 里的大堆一起导致交换。 ### 5. 只...
(YU7_YU8)
🪛 markdownlint-cli2 (0.20.0)
[warning] 121-121: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 121-121: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 121-121: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 121-121: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
🤖 Prompt for AI Agents
In `@docs/BUILD-ACCELERATION.md` around lines 1 - 141, The document "ZStack
构建加速指南" is written in Chinese but the repo requires English-only documentation;
please convert this file to English (or add a complete English version alongside
the Chinese) so all headings (e.g., "ZStack 构建加速指南"), section titles, prose, and
any inline comments are in correct English and free of spelling errors; keep
command examples and flags unchanged, preserve technical details (mvnd/mvn
usage, profiles, flags like -P premium, -Dmevoco.skip.obfuscate=true,
.mvn/jvm.config settings, and plugin notes such as gmavenplus fork) and, if you
retain the Chinese version, add a clear bilingual header indicating both
languages and ensure filenames/links referenced in the text remain consistent.
| job = (LongJob) it.getConstructor().newInstance(); | ||
| } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { | ||
| e.printStackTrace(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
反射调用更新正确,但异常处理应使用日志而非 printStackTrace()。
使用 e.printStackTrace() 将异常输出到标准错误流不是最佳实践,应该使用已有的 logger 进行记录。
🛠️ 建议的修复方案
try {
job = (LongJob) it.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
- e.printStackTrace();
+ logger.warn(String.format("failed to instantiate LongJob class[%s]", it.getName()), e);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| job = (LongJob) it.getConstructor().newInstance(); | |
| } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { | |
| e.printStackTrace(); | |
| } | |
| job = (LongJob) it.getConstructor().newInstance(); | |
| } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { | |
| logger.warn(String.format("failed to instantiate LongJob class[%s]", it.getName()), e); | |
| } |
🤖 Prompt for AI Agents
In `@longjob/src/main/java/org/zstack/longjob/LongJobFactoryImpl.java` around
lines 54 - 57, The catch block in LongJobFactoryImpl that handles
InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException currently calls e.printStackTrace(); replace this with
a proper logger call (e.g., logger.error("Failed to instantiate LongJob via
reflection for " + it.getName(), e)) so the exception is recorded via the class
logger; update the catch to log the exception and any contextual info (the
constructor/type or variable job) instead of printing the stack trace.
ZQLImpact
Change-Id: I656f6963726b77727363656d756465766b6a7a6a
sync from gitlab !9100