EPICS Archiver Appliance源码进阶

一、获取源码

码地址是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),而是使用 GroovyKotlin 语言来编写脚本(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

  1. Ubuntu/Debian:sudo apt install gradle
  2. 手动安装时记得chmod +x授权执行
  3. 验证安装: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

这将启动应用程序,访问 appliance0appliance1

要关闭正在运行的应用程序,可以按下 Ctrl-C(中断命令),然后运行:

Kotlin 复制代码
gradle shutdownAllTomcats

这会关闭所有运行中的 Tomcat 实例,而不仅仅是通过 gradle testRun 启动的实例。它对中断集成测试时特别有用。


部署

快速部署:

对于单个设备的快速部署,按如下步骤进行:

  1. 下载最新的发行版本并解压到一个名为 archiver 的文件夹。

  2. 在同一文件夹中,下载 Tomcat 11 的发布版(无需解压)。

  3. 将从解压的发布版本中获得的 quickstart.sh 文件复制到该文件夹。

  4. 运行 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。

    Kotlin 复制代码
    java {
        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") }
}

(二)

相关推荐
罗小爬EX2 小时前
升级IDEA 2025.3+后 Spring Boot 配置文件自动提示插件推荐
java·spring boot·intellij-idea
haiyu柠檬18 小时前
IDEA和VSCode中好用的插件推荐
java·vscode·intellij-idea
ss27321 小时前
idea中git更新项目:将传入更改合并到当前分支,在传入更改上变基当前分支
java·git·intellij-idea
m0_579146651 天前
Maven 编译的settings配置和pom、idea配置关系
java·maven·intellij-idea
smileSunshineMan1 天前
idea启动kafka源码
java·kafka·intellij-idea
烤麻辣烫1 天前
java进阶--刷题与详解-1
java·开发语言·学习·intellij-idea
计算机毕设指导61 天前
基于微信小程序的社区医疗服务管理系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
lonelyhiker2 天前
IDEA未编译完就启动项目的问题
java·ide·intellij-idea
代码改变生活-1202 天前
idea 清除缓存之后重启项目编译失败
java·缓存·intellij-idea