Ohhnews

分类导航

$ cd ..
foojay原文

新版Foojay博客平台支持使用AsciiDoc撰写文章

#asciidoc#markdown#foojay#技术写作#文档格式

Markdown 是一个不错的默认选择。它易于编写,人人都已经会,而且对大多数文章来说完全够用。
但对某些文章来说并非如此。如果你曾经想给代码块加标题、给感兴趣的行编号并在下方解释,或者把警告与上一段区分开,那么你就触及了 Markdown 的极限。
Java 生态中有很大一部分正是出于这个原因而使用 AsciiDoc 编写文档。所以,在新的由 Hugo 驱动的 Foojay 上,文章现在也可以用 AsciiDoc 来写。感谢 Brice Dutheil 请求加入此功能,并明确列出了他使用它的哪些部分。当然,这篇文章就是用 AsciiDoc 写的,以此展示它!

简要版本

将文件命名为 index.adoc,而不是 index.md。整个切换就是这样。

content/posts/2026/10/09/my-article/
├── index.adoc
└── screenshot.png

frontmatter(前置元数据)块完全相同:titledateauthorscategories,用 --- 包围。图片仍然放在文章旁边。同样的检查会在你的 pull request 上运行。提交文章的其他方面没有任何变化。

命名块

块可以带标题,写法是以点号开头的单独一行:

$ asciidoc
.配置执行器
[source,java]
----
var executor = Executors.newVirtualThreadPerTaskExecutor();
----

渲染为:
配置执行器

$ java
var executor = Executors.newVirtualThreadPerTaskExecutor();

任何块都可以命名:表格、图片和引用。

源代码中的标注

这是 Markdown 完全没有对应功能的一项。在代码中放置编号标记,并在下方解释它们:

$ asciidoc
[source,java]
----
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {  // <1>
    var user  = scope.fork(() -> findUser(id));                  // <2>
    scope.join().throwIfFailed();                                // <3>
    return user.get();
}
----
<1> 作用域拥有在其中派生的每个任务。
<2> `fork` 会立即返回;此时还没有任何任务运行。
<3> `join` 会等待所有任务,并重新抛出第一个失败。

标记放在该代码片段所用语言的注释中 —— Java 用 //,shell 或 Python 片段用 #,SQL 用 --。这样,如果你把片段粘贴回 IDE 检查,文件仍然可以编译。注释本身不会到达读者那里:它会变成一个带圈数字,并且标记会与下方的解释对齐,这样以后编辑片段时,两者都不会彼此错位。结果看起来像这样:

$ java
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {    var user  = scope.fork(() -> findUser(id));    scope.join().throwIfFailed();    return user.get();
}
  1. 作用域拥有在其中派生的每个任务。

  2. fork 会立即返回;此时还没有任何任务运行。

  3. join 会等待所有任务,并重新抛出第一个失败。

告诫框

告诫框是带标签的方框,用来把一段备注与周围的段落区分开。这是 AsciiDoc 使用的一个特定术语。共有五种,每一种都写成一个单词后跟一个冒号:

$ asciidoc
NOTE: 虚拟线程不是更快的线程。它们是更便宜的线程。

TIP: `jcmd <pid> Thread.dump_to_file` 可以列出每一个虚拟线程。

WARNING: 在 JDK 24 之前,`synchronized` 块仍会固定载体线程。

CAUTION: 不要过度使用这类块...

IMPORTANT: 这条消息会被特别高亮显示!

结果:

类型内容
注意虚拟线程不是更快的线程。它们是更便宜的线程。
提示jcmd <pid> Thread.dump_to_file 可以列出每一个虚拟线程。
警告在 JDK 24 之前,synchronized 块仍会固定载体线程。
小心不要过度使用这类块...
重要这条消息会被特别高亮显示!

文本必须与标签位于同一行。之后它可以换行成任意多行,但如果标签单独占一行,那就根本不是告诫框,而只是一个碰巧以“TIP:”这个词开头的段落。
对于其中包含空行的内容,你需要使用另一种形式:把标签放在方括号中单独一行,位于 ==== 块的上方。

$ asciidoc
[TIP]
====
虚拟线程创建成本低,但阻塞并非免费。在 JDK 24 之前,一个停放在 `synchronized` 监视器上的线程会固定其载体线程,因此底层平台线程池仍然可能被看起来非阻塞的代码耗尽。

凡是你原本会写 `synchronized` 的地方,改用 `ReentrantLock`,并在假设自己用的是哪一种之前,用 `jcmd <pid> Thread.dump_to_file -format=json` 测量一下。
====

结果:

类型内容
提示虚拟线程创建成本低,但阻塞并非免费。在 JDK 24 之前,一个停放在 synchronized 监视器上的线程会固定其载体线程,因此底层平台线程池仍然可能被看起来非阻塞的代码耗尽。凡是你原本会写 synchronized 的地方,改用 ReentrantLock,并在假设自己用的是哪一种之前,用 jcmd <pid> Thread.dump_to_file -format=json 测量一下。

不只是网格的表格

Markdown 表格只是单元格组成的网格,仅此而已。AsciiDoc 表格可以设置列宽、合并单元格,以及按列对齐:

$ asciidoc
.垃圾收集器概览
[cols="<1,^1,>1,2", options="header"]
|===
| 收集器 | 分代 | 典型停顿 | 最适合

| Serial || 100ms+ | 小堆、单核
| G1     || ~200ms | 一般场景
| ZGC    || 1ms | 大堆、延迟敏感服务
|===

结果:

收集器分代典型停顿最适合
Serial100ms+小堆、单核
G1~200ms一般场景
ZGC1ms大堆、延迟敏感服务
[表 1. 垃圾收集器概览]

cols 属性完成了所有这些。数字是相对宽度,所以最后一列的宽度是其他列的两倍,因为它容纳的文本量是两倍。每个数字前面的符号设置对齐方式:< 左对齐,^ 居中对齐,> 右对齐;这正是数字能彼此对齐,而说明文字仍保持左对齐的原因。
单元格也可以合并,而这正是 Markdown 完全无法应对的部分。| 前面的前缀表示单元格跨越的范围:3+| 跨三列,.2+| 跨两行,2.2+| 两者都跨。

$ asciidoc
.JDK 支持窗口
[cols="1,1,2,1", options="header"]
|===
| 版本 | 类型 | 供应商支持 | 结束

| Java 21 | LTS  .2+| 所有主要供应商 | 2031
| Java 25 | LTS | 2035
3+| Java 26 和 27 —— 非 LTS,各六个月 | 2027
|===

结果:

版本类型供应商支持结束
Java 21LTS所有主要供应商2031
Java 25LTS所有主要供应商2035
Java 26 和 27 —— 非 LTS,各六个月2027
[表 2. JDK 支持窗口]

“所有主要供应商”是一个跨两行的单元格,而最后一行是一个跨三列的单元格。两者都只多花几个字符。

其他一切都保持不变

网站围绕文章所做的一切都以相同方式工作。“本页”导航由你的 == 标题构建。图片放在文章文件夹中,并会检查大小和替代文本。frontmatter 规则还是同样的规则,由你的 pull request 上同样的检查强制执行。
代码由同一个高亮器高亮,语言名称也相同,因此这里的 [source,kotlin] 和 Markdown 文章中的 ```kotlin 围栏最终看起来完全一样。
而且 Mermaid 图表 也可以工作,像任何其他源块一样:

$ asciidoc
[source,mermaid]
----
graph LR
    A[Source] --> B[javac]
    B --> C[Bytecode]
----

结果:

$ mermaid
graph LR
    A[Source] --> B[javac]
    B --> C[Bytecode]

你应该用哪一种?

Markdown,除非你有理由不用它。对于普通散文式内容,它更简短,也更容易审阅。
当文章承载真正的技术分量时,就该用 AsciiDoc:代码需要逐行注释的演练教程、需要合适表格的对比、警告多到应该让它们看起来就像警告的文章。这正是该格式的用途,而现在它只差一个文件扩展名。

发现错误,或有内容要补充?在 GitHub 上编辑此页 [LOADING...]
作者

Frank Delporte

Frank Delporte 是 Java Champion、Java 开发者、Azul 高级技术文档工程师、博主、《Java Programming for Raspberry Pi - A Hands-On Guide to Electronics and IoT Projects》作者,以及 Pi4J、Lottie4J、Sheetmusic4J 等项目的开源贡献者……

相关文章

Foojay [LOADING...]
Frank Delporte 2026年9月22日 297 次浏览

宣布新版 Foojay

Foojay Foojay [LOADING...]
3 位作者 2022年5月3日 15,297 次浏览

如何在 Foojay.io 上提交你的下一篇文章

Foojay

加入讨论

Foojay [LOADING...]
Frank Delporte 2026年9月22日 297 次浏览

宣布新版 Foojay

Foojay Foojay [LOADING...]
3 位作者 2022年5月3日 15,297 次浏览

如何在 Foojay.io 上提交你的下一篇文章

Foojay