一、获取源码
码地址是https://github.com/archiver-appliance/epicsarchiverap

下载zip格式的代码,并解压到本地的文件夹。
通过IDEA的open as project打开。文件目录如下:

二、构建工具
源码的构建工具是gradle不是我常用的maven。如果编译器使用的是IDEA,在IDEA中已经集成了gradle插件,无需单独安装gradle。可以跳过本环节。

需要了解一下gradle工具的继续本节。
1.gradle是什么?
Gradle 是一个非常强大的自动化构建工具。可以下载所需的代码库(依赖管理)、编译代码、运行测试、以及最后打包发布应用。
与maven相比,gradle有以下优势:
- 基于 Groovy/Kotlin 的 DSL: 它不使用繁琐的 XML 配置文件(像 Maven 的 pom.xml),而是使用 Groovy 或 Kotlin 语言来编写脚本(
build.gradle)。这使得配置更简洁、灵活,且具有编程能力。 - 构建速度快: 它采用了"增量构建"、构建缓存和并行编译技术,能跳过未改变的部分,只编译修改过的代码,大大提升了构建速度。
- 强大的依赖管理: 它能自动从 Maven、Ivy 等远程仓库下载项目所需的库(Jar 包),并处理复杂的依赖冲突。
- 插件化架构: 功能通过插件扩展。例如,
java插件提供编译 Java 代码的能力,com.android.application插件用于构建 Android 应用。
2.gradle怎么用?
第一步:安装配置(windows)
1.已安装JDK
2.去gradle官网下载.zip安装包,我安装的这个太大了,可以安装binary-only

3.解压安装到路径下D:\Install\gradle-8.0
4.配置环境变量:新建系统变量 GRADLE_HOME,值为解压路径D:\Install\gradle-8.0。在系统变量 Path 中添加 %GRADLE_HOME%\bin。
5.测试安装是否成功:打开命令行(cmd),输入 gradle -v。如果看到版本信息(如 Gradle 8.5),说明安装成功。

Tips:虽然可以全局安装,但在实际团队开发中,更推荐使用 Gradle Wrapper(包装器)。它允许项目自带 Gradle 版本,避免团队成员因版本不同导致构建失败。你只需要运行 gradle wrapper 命令,项目中就会生成 gradlew.bat(Windows)或 gradlew(Mac/Linux)脚本,以后直接用这个脚本执行命令即可。
linux安装gradle
- Ubuntu/Debian:
sudo apt install gradle - 手动安装时记得
chmod +x授权执行 - 验证安装:gradle -v应显示版本信息
第二步:常用命令
| 命令 | 作用说明 |
| `gradle tasks` | 列出项目中所有可用的构建任务。 |
| `gradle build` | 最常用。执行完整的构建流程(编译、测试、打包)。 |
| `gradle clean` | 清理构建目录(删除 `build` 文件夹),为重新构建做准备。 |
| `gradle assemble` | 仅执行打包任务(如生成 JAR 或 APK 文件),不运行测试。 |
| `gradle test` | 仅编译并运行单元测试,生成测试报告。 |
第三步:编写构建脚本build.gradle
Kotlin
// 1. 应用插件:引入 Java 构建功能和 IDEA 支持
plugins {
id 'java'
id 'idea'
}
// 2. 仓库配置:告诉 Gradle 去哪里下载依赖
repositories {
mavenCentral() // 使用 Maven 中央仓库
}
// 3. 依赖管理:声明项目需要的外部库
dependencies {
// 编译时依赖(implementation):项目代码需要
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.5'
// 测试时依赖(testImplementation):只有测试代码需要
testImplementation 'junit:junit:4.13'
}
// 4. 自定义任务(可选)
task hello {
doLast {
println 'Hello, Gradle!'
}
}
代码解释:
Plugins (插件): 决定了这个项目能干什么。加了 java 插件,Gradle 才知道如何编译 .java 文件。
Repositories (仓库): 类似于"应用商店",Gradle 会去这里找你要的库。
Dependencies (依赖): 依赖的jar包。implementation 表示这个依赖只在编译和运行时生效;testImplementation 表示只在跑测试时生效。
Task (任务): 你可以自定义任务,比如上面的 hello 任务,输入 gradle hello 就会在控制台打印一句话。
第四步:gradle项目目录

其中:
.gradleGRADLE用于存储缓存和构建过程文件的地方。不提交到git
.idea IDEA创建的项目配置目录。不提交到git
gradle存放gradle wrapper配置和相关文件的专用目录
build.gradle.kts是gradle使用kotlin编写的项目构建脚本文件,是项目构建的主要文件
gradlew是gradle wrapper的脚本文件。适用于linux系统。会读取gradle-wrapper.properties执行构建任务
gradlew.bat是gradle wrapper的脚本文件。适用于windows系统。会读取gradle-wrapper.properties执行构建任务
src源码
settings,gradle.kts是kotlin编写的设置脚本文件

三、工程目录

四、README.md
EPICS Archiver Appliance - 详细介绍
EPICS Archiver Appliance 是一个用于 EPICS 控制系统的归档实现,旨在存档大量的过程变量(PVs)。该项目的目标是处理数百万个数据点,并且具备如下主要特点:
主要功能:
-
集群能力:能够通过添加新的设备到集群来扩展归档系统的能力。
-
多阶段数据处理:内置多个存储阶段,以及数据在各阶段之间的迁移机制。
-
数据检索性能:优化数据检索操作的效率,确保快速的查询响应。
-
零监管(Zero oversight):尽量减少需要人工干预的操作,系统尽可能地自动化。
如需进一步了解,请查阅项目文档或当前分支的文档。
开发和构建指南
开发工具:
EPICS Archiver Appliance 使用 Gradle 作为构建工具。你可以使用 Gradle Wrapper (./gradlew),它会自动下载适合的 Gradle 版本,或者你也可以安装本地 Gradle 版本并确保版本大于 gradle-wrapper.properties 中的版本号。
构建:
要构建项目,只需要运行以下命令:
Kotlin
gradle
构建完成后,生成的分发包将位于**build/distributions** 目录中。如果你需要为特定站点构建一个定制版本,可以通过设置环境变量 ARCHAPPL_SITEID 来指定 src/sitespecific 目录下的站点特定文件夹。例如,你可以使用 src/sitespecific/slacdev 中的示例进行定制。
代码格式化
该项目使用 Spotless 插件来确保代码风格的一致性,支持 Java 代码和 Web 代码(如 HTML、CSS 和 JavaScript)。新的代码会与 origin/master(在 CI 中可能与本地 origin 不同)进行格式化检查。
格式化代码:
要格式化新代码,可以运行以下命令:
Kotlin
gradle spotlessApply
要检查代码是否符合格式要求,可以运行:
Kotlin
gradle spotlessCheck
测试
测试在项目中分为多个类别,包括:"slow"(慢速测试)、"integration"(集成测试)、"localEpics"(本地 EPICS 测试)、"flaky"(偶尔失败的测试)、"singleFork"(每个测试单独运行)、和 "unit"(单元测试)。
单元测试:
要运行单元测试(这些是构建过程中的必需步骤):
Kotlin
gradle test
要运行某个特定的测试(例如,TestName):
Kotlin
gradle test --tests "org.epics.archiverappliance.TestName"
要运行包括 "flaky" 和 "slow" 测试的命令:
Kotlin
gradle unitTests
集成测试:
集成测试要求安装 Tomcat,并且只能支持到 Tomcat 11 版本。需要设置环境变量 TOMCAT_HOME,并确保 conf 目录存在。
要运行本地 EPICS 安装所需的测试:
Kotlin
gradle epicsTests
你也可以使用 Docker 镜像来运行 EPICS 测试:
Kotlin
docker compose -f docker/docker-compose.epicsTests.yml run epicsarchiver-test
集成测试会生成大量的磁盘数据,因此建议不要一次性运行所有集成测试。如果你想运行某个特定的集成测试:
Kotlin
gradle integrationTests --tests "org.epics.archiverappliance.retrieval.DataRetrievalServletTest"
测试运行:
如果你只是想运行应用程序并手动测试新开发的功能,可以使用以下命令:
Kotlin
gradle testRun
这将启动应用程序,访问 appliance0 和 appliance1。
要关闭正在运行的应用程序,可以按下 Ctrl-C(中断命令),然后运行:
Kotlin
gradle shutdownAllTomcats
这会关闭所有运行中的 Tomcat 实例,而不仅仅是通过 gradle testRun 启动的实例。它对中断集成测试时特别有用。
部署
快速部署:
对于单个设备的快速部署,按如下步骤进行:
-
下载最新的发行版本并解压到一个名为
archiver的文件夹。 -
在同一文件夹中,下载 Tomcat 11 的发布版(无需解压)。
-
将从解压的发布版本中获得的
quickstart.sh文件复制到该文件夹。 -
运行
quickstart.sh脚本:
bash
./quickstart.sh apache-tomcat-11.*.tar.gz
更多关于部署的信息,请参考 quickstart 文档。对于复杂的部署方式,可以查看 samples 文件夹中的示例。
构建文档
网站文档使用 Read the Docs 构建。如果你想在本地构建并运行文档,请执行以下操作:
1.进入 docs 目录:
bash
cd docs
2.创建并激活 Python 虚拟环境:
bash
python -m venv .venv source .venv/bin/activate
3.安装所需的 Python 包:
bash
python -m pip install --upgrade --no-cache-dir pip setuptools python -m pip install --upgrade --no-cache-dir sphinx readthedocs-sphinx-ext python -m pip install --exists-action=w --no-cache-dir -r docs/requirements.txt
4.进入 docs 目录并启动文档构建:
bash
cd docs sphinx-autobuild source build
这将启动一个自动构建的文档服务器,你可以在浏览器中查看构建的文档。
五、代码解读
(一)build.gradle.kts构建文件
首先是构建文件build.gradle.kts文件。该文件是使用 Gradle Kotlin DSL 编写的,定义了该项目的构建过程、依赖管理、任务以及一些代码质量和格式化的配置。
1.插件和任务定义
-
java-library:用于构建 Java 库项目。 -
war:支持构建 Web 应用程序的 WAR 文件。 -
eclipse:为 Eclipse IDE 生成项目配置。 -
ca.cutterslade.analyze:分析项目的依赖关系,查看是否有未使用的依赖。 -
com.palantir.git-version:用于从 Git 获取版本信息。 -
com.diffplug.spotless:用于代码格式化,确保代码的风格一致。 -
com.google.protobuf:用于处理 Protocol Buffers 文件。
Kotlin
plugins {
`java-library`
war
eclipse
id("ca.cutterslade.analyze") version "1.9.2"
id("com.palantir.git-version") version "3.0.0"
id("com.diffplug.spotless") version "6.25.0"
id("com.google.protobuf") version "0.9.5"
}
2.配置项目的源代码目录
- sourceSets 配置了项目的源代码目录,其中包括 Java 源代码和 Proto 文件。
- main 源集指明了 Java 和 Proto 文件的目录。
- test 源集指定了测试源代码的目录。
Kotlin
sourceSets {
main {
java {
srcDir("src/main/")
}
proto {
srcDir("src/proto")
}
resources {
setSrcDirs(emptyList<String>())
}
}
test {
java {
srcDir("src/test/")
}
resources {
setSrcDirs(emptyList<String>())
}
}
}
3.java版本和工具链
-
该部分指定了使用 Java 21 版本,确保构建时使用合适的 JDK。
Kotlinjava { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } }
4.git版本和版本号设置
- 从 Git 获取项目的版本号。如果 Git 无法正常工作(例如,未初始化或无法访问),则使用
projVersion属性或设置版本为 "unknown"。
Kotlin
val gitVersion: groovy.lang.Closure<String> by extra
val versionDetails: groovy.lang.Closure<VersionDetails> by extra
var gitWorks = true
try {
version = gitVersion()
} catch (e: Throwable) {
gitWorks = false
if (project.hasProperty("projVersion")) {
version = project.property("projVersion") as String
} else {
version = "unknown"
logger.error("Failed to get git version: $e")
}
}
5.构建目录和站点特定内容
- 定义了 stageDir、archapplsite 和 sitespecificpath,用于存放构建的内容和站点特定的配置。
Kotlin
val stageDir = layout.buildDirectory.file("stage").get()
val archapplsite = System.getenv("ARCHAPPL_SITEID") ?: "tests"
val defaultsitespecificpath = "src/sitespecific/$archapplsite"
val sitespecificpath =
if (file(defaultsitespecificpath).exists()) defaultsitespecificpath else archapplsite
6.依赖管理
- 使用了多个外部依赖,包括 EPICS、Redis、Guava、Hazelcast 等,以及用于测试的 JUnit 等。
- 本地 JAR 文件和从 GitHub 或 Maven 中下载的依赖也被添加到项目中。
Kotlin
dependencies {
implementation(files("lib/jamtio_071005.jar", "lib/redisnio_0.0.1.jar"))
viewer("archiver-appliance:svg_viewer:v1.2.1@zip")
implementation("org.epics:jca:2.4.7")
implementation("com.google.guava:guava:33.5.0-jre")
implementation("com.hazelcast:hazelcast:5.5.0")
implementation("redis.clients:jedis:7.0.0")
implementation("org.python:jython-standalone:2.7.3")
implementation("com.google.protobuf:protobuf-java:${findProperty("protobufJavaVersion")}")
implementation("org.phoebus:core-pva:5.0.2")
runtimeOnly("org.mariadb.jdbc:mariadb-java-client:3.3.3")
testImplementation("org.junit.jupiter:junit-jupiter-api:${findProperty("junitJupiterVersion")}")
}
7.编译和构建任务
- generateReleaseNotes 任务:该任务生成发布说明,使用 Git 提供的日志生成发布的变更记录。
Kotlin
tasks.register<Exec>("generateReleaseNotes") {
group = "Staging"
description = "Generate the Release Notes."
outputs.file("$stageDir/RELEASE_NOTES")
doFirst { standardOutput = FileOutputStream("$stageDir/RELEASE_NOTES") }
commandLine("git", "log", "--oneline", "HEAD")
isIgnoreExitValue = true
}
buildRelease任务:用于打包构建的 WAR 文件并将其压缩成一个.tar.gz文件。
Kotlin
tasks.register<Tar>("buildRelease") {
group = "Wars"
description = "Builds a full release and zips up in a tar file."
dependsOn("mgmtWar", "retrievalWar", "etlWar", "engineWar", "generateReleaseNotes")
archiveFileName.set("archappl_v${version}.tar.gz")
compression = Compression.GZIP
from(layout.buildDirectory.file("libs/mgmt.war"))
from(layout.buildDirectory.file("libs/engine.war"))
from(layout.buildDirectory.file("libs/etl.war"))
from(layout.buildDirectory.file("libs/retrieval.war"))
from(project.projectDir) {
include("LICENSE", "NOTICE", "*License.txt", "RELEASE_NOTES")
}
}
8.代码质量与格式化
- 使用
Spotless插件来确保代码格式一致性,包括.gradle.kts、.md、HTML、CSS 等文件的格式化。
Kotlin
configure<SpotlessExtension> {
format("misc") {
target("*.gradle.kts", "*.md", ".gitignore")
trimTrailingWhitespace()
indentWithTabs()
endWithNewline()
}
format("styling") {
target(
"docs/docs/source/**/*.html",
"docs/docs/source/**/*.css",
"docs/docs/source/**/*.md",
"docs/**/docs.js",
"src/main/**/*.html",
"src/main/**/*.js",
"src/main/**/*.css"
)
prettier()
}
}
9.测试任务
配置了测试任务,限制了并行运行的测试数目,并设置了 JVM 参数。
Kotlin
tasks.withType<Test>().configureEach {
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
doFirst {
temporaryDir.resolve("sts").mkdirs()
temporaryDir.resolve("mts").mkdirs()
temporaryDir.resolve("lts").mkdirs()
}
filter {
includeTestsMatching("*Test")
}
maxHeapSize = "1G"
jvmArgs = listOf("-Dlog4j1.compatibility=true")
environment("ARCHAPPL_SHORT_TERM_FOLDER", temporaryDir.resolve("sts").path)
}
10.打包和部署War文件
- 配置了多个 WAR 文件构建任务,用于构建不同的 WAR 文件(如 mgmt.war、retrieval.war、etl.war)。
Kotlin
tasks.withType<War>().configureEach {
dependsOn("stage", "sitespecificantscript")
from(stageDir.asFile.resolve("org/epics/archiverappliance/staticcontent")) { into("ui/comm") }
}