Apache Juneau 配置参数详解
按层级梳理 Apache Juneau 9.2.0 序列化/解析 Builder 参数、Bean/REST 注解参数、微服务 cfg 与 jetty.xml 配置项,全部参数经真实运行实测,含生产参数模板与 FAQ。
Apache Juneau 配置参数详解
目标:Juneau 的参数分散在四个层级——序列化/解析器 Builder 参数、Bean 注解参数、REST 服务端注解参数、微服务配置文件(demo.cfg/jetty.xml/JVM)。本文基于 9.2.0 实测逐类梳理,所有参数行为均来自真实运行回显(环境:Ubuntu 22.04.5 LTS + JDK 17.0.20.1 + Maven 3.6.3,演示服务监听 10000 端口),并给出可直接复制的生产参数模板。
一、参数体系概览
| 层级 | 载体 | 典型参数 | 生效范围 |
|---|---|---|---|
| Builder 参数 | JsonSerializer.create().ws()... 等 | ws/sq/ns/addRootType、ignoreUnknownBeanProperties、sortProperties | 单个序列化器/解析器实例 |
| Bean 注解 | @Bean/@Swap(org.apache.juneau.annotation 包) | typeName/properties/sort/interceptor | 单个 Bean 类 |
| REST 注解 | @Rest/@RestGet/@RestPost/@Path/@Query/@Content | path/summary/produces/consumes/defaultCharset | 单个 REST 资源与方法 |
| 微服务配置 | demo.cfg、jetty.xml、JVM 参数 | Jetty/port、resolveVars、maxThreads、-Xms/-Xmx | 整个微服务进程 |
参数的权威查看方式(本文实测采用):
javap反编译 jar 查 Builder/注解的真实方法签名(9.2.0 相比旧版有增删,以字节码为准);- 请求不支持的媒体类型,406 报错正文会回显全部支持媒体类型;
- 运行期把演示服务跑起来,用 curl 验证参数真实效果。
二、序列化与解析参数
2.1 序列化器 Builder 公共参数(实测)
以 JsonSerializer 为例,XxxSerializer.create() 返回 Builder,实测可用的公共参数:
| Builder 方法 | 参数含义 | 实测效果 |
|---|---|---|
ws() | useWhitespace,输出带缩进换行 | JSON 输出多行缩进(Tab 缩进) |
sq() | 单引号代替双引号 | {'id':1001,'name':'beibei',...} |
ns() | XML 命名空间模式(XmlSerializer) | 输出 <Pet>...</Pet> 带命名空间结构 |
addRootType() | 根对象输出 _type 字典类型 | " soldDate":... 前多了 "_type": "Pet" |
addBeanTypes() | 全部对象输出 _type(根对象默认不加,仅集合内 Bean 加) | 实测根对象无变化 |
keepNullProperties()/sortProperties() 等 | 继承自 BeanContext.Builder,见 2.2 | — |
实测回显(12 段演示的关键两段,完整回显见安装指南 4.7):
=== [1] JsonSerializer 可读格式(ws) ===
{
"id": 1001,
"name": "beibei",
"price": 599.0,
"soldDate": "1970-01-01T00:00:00",
"status": "PENDING",
"tags": [
"golden",
"young"
]
}
=== [2] JsonSerializer 紧凑格式 + 单引号(sq) ===
{'id':1001,'name':'beibei','price':599.0,'soldDate':'1970-01-01T00:00:00','status':'PENDING','tags':['golden','young']}
addRootType() 实测回显:
=== [12] _type 字典类型(@Bean typeName + addRootType) ===
{
"_type": "Pet",
"id": 1001,
"name": "beibei",
"price": 599.0,
"soldDate": "1970-01-01T00:00:00",
"status": "PENDING",
"tags": [
"golden",
"young"
]
}
按 _type 还原: id=1001 name=beibei
⚠️ 9.2.0 中
JsonSerializer.Builder已无旧版的simple()(键不加引号的 simple JSON 模式)方法;单引号键值用sq(),键仍带引号。
2.2 BeanContext 全局参数(实测 javap 完整清单)
BeanContext.Builder(所有序列化器/解析器 Builder 的父接口)在 9.2.0 的无参开关方法完整清单:
beanMapPutReturnsOldValue() beansRequireDefaultConstructor() beansRequireSerializable()
beansRequireSettersForGetters() debug() disableBeansRequireSomeProperties()
disableIgnoreMissingSetters() disableIgnoreTransientFields()
disableIgnoreUnknownNullBeanProperties() disableInterfaceProxies()
findFluentSetters() ignoreInvocationExceptionsOnGetters()
ignoreInvocationExceptionsOnSetters() ignoreUnknownBeanProperties()
ignoreUnknownEnumValues() sortProperties() useEnumNames() useJavaBeanIntrospector()
高频参数实测:
ignoreUnknownBeanProperties()——默认关闭时,解析含未知属性的 JSON 直接报错:
=== [1] 默认 parser 遇到未知属性 ===
异常: Unknown property 'unknown' encountered while trying to parse into class 'com.example.ConfigDemo$Pet'
At: line 1, column 19
While parsing into:
currentClass: Object
---start--
1: {"id":1,"name":"a","unknown":"x"}
---end--
开启后解析成功:
=== [2] ignoreUnknownBeanProperties(true) ===
com.example.ConfigDemo$Pet@10a035a0
sortProperties()——全局按属性名字母序输出(与 @Bean(sort=true) 等效的全局开关)。
2.3 相比旧版本已移除的参数(重要)
实测 9.2.0 的 BeanContext.Builder 中不存在以下旧版方法,迁移时需注意:
bpi(String)(按类限定序列化属性)——改用@Bean(properties="id")注解;trimStrings()、keepNullProperties()——9.2.0 已删除。
⚠️ 另注意:
@Bean.properties的类型是String(逗号分隔),不是旧版的String[],写成@Bean(properties={"id"})会编译报错annotation value not of an allowable type(实测)。
三、Bean 注解参数
3.1 @Bean 完整属性(实测 javap 9.2.0)
@Bean 位于 org.apache.juneau.annotation 包(旧版本在 org.apache.juneau 根包,9.2.0 请勿导错包)。属性清单:
| 属性 | 类型 | 说明 | 实测 |
|---|---|---|---|
typeName | String | 字典类型名,配合 addRootType() 输出 _type | ✔ _type: "Pet" |
typePropertyName | String | _type 键名自定义 | — |
properties | String | 逗号分隔的属性白名单(注意是 String) | ✔ properties="id" 只输出 id |
excludeProperties/xp | String | 属性黑名单 | — |
readOnlyProperties/ro | String | 只读属性 | — |
writeOnlyProperties/wo | String | 只写属性 | — |
p | String | properties 的别名 | — |
sort | boolean | 属性按字母序输出 | ✔ 输出 id,name,price,soldDate,status,tags |
findFluentSetters | boolean | 识别链式 setter | — |
interceptor | Class | BeanInterceptor 拦截器 | — |
propertyNamer | Class | PropertyNamer 属性重命名 | — |
dictionary | Class[] | 类型字典 | — |
implClass/interfaceClass/stopClass | Class | 实现类/接口映射/终止类 | — |
description/example | String[]/String | 文档与示例元数据 | — |
on/onClass | String[]/Class[] | 作用于指定成员 | — |
实测回显:
=== [3] @Bean(properties="id") 限定序列化属性 ===
{"id":7}
=== [5] @Bean(sort=true) 注解级排序 ===
{"id":1001,"name":"beibei","price":599.0,"soldDate":"1970-01-01T00:00:00","status":"PENDING","tags":["golden"]}
(声明顺序为 id,name,tags,price,status,soldDate,输出已按字母序重排,证明 sort=true 生效。)
3.2 @Swap 与 StringSwap(自定义转换器)
@Swap(XxxSwap.class) 可标注在字段/Bean 上,StringSwap 子类只需实现 swap(BeanSession, String):
/** 自定义 Swap:姓名首字母保留、其余打码 */
public static class NameMaskSwap extends StringSwap<String> {
@Override
public String swap(BeanSession session, String o) {
return o.charAt(0) + "**";
}
}
@Bean(typeName="Owner")
public static class Owner {
@Swap(NameMaskSwap.class)
public String realName = "zhangsan";
public int level = 3;
}
实测回显:
=== [9] @Swap 注解(NameMaskSwap) ===
{
"level": 3,
"realName": "z**"
}
3.3 内置日期交换
java.util.Date 无需配置,Juneau 内置交换器默认输出 yyyy-MM-ddTHH:mm:ss 格式字符串,且可被解析还原(实测 [10] 段 soldDate=Thu Jan 01 00:00:00 GMT 1970 还原成功)。
四、REST 服务端参数
4.1 @Rest 资源级参数(实测 javap 9.2.0 常用子集)
@Rest 位于 org.apache.juneau.rest.annotation 包(juneau-rest-server 构件)。常用属性:
| 属性 | 说明 | 实测 |
|---|---|---|
path | 资源根路径 | ✔ path="/" |
title | 页面/文档标题 | ✔ curl 默认页面 <h1>Juneau 宠物商店示例服务</h1> |
description | 资源描述 | ✔ |
children | 子资源类数组 | — |
serializers/parsers | 自定义序列化器/解析器列表 | — |
produces/consumes | 支持的媒体类型 | — |
defaultAccept/defaultContentType | 默认 Accept/Content-Type | — |
defaultCharset | 默认响应字符集(实测默认 utf-8) | ✔ 响应头 charset=utf-8 |
maxInput | 最大请求体 | — |
config | 关联 Config 配置 | — |
debug/debugOn | 调试开关 | — |
roleGuard/rolesDeclared | 角色鉴权 | — |
staticFiles/encoders/guards/converters | 静态文件/压缩/守卫/转换器 | — |
4.2 方法级注解参数
| 注解/参数 | 说明 | 实测 |
|---|---|---|
@RestGet(path=..., summary=...) | GET 方法声明;summary 进入 HTML 页面与 OpenAPI | ✔ /pet/{id} |
@RestPost(path=...) | POST 方法声明 | ✔ /pet |
@Path("id") int id | 路径参数绑定 | ✔ GET /pet/1001 → id=1001 |
@Query(name="name", def="stranger") String name | 查询参数绑定,def 为默认值 | ✔ 无参请求返回 "Hello, stranger!" 类回显 |
@Content Pet pet | 请求体绑定(9.2.0 由旧版 @Body 更名) | ✔ POST JSON 反序列化为 Pet |
实测 /greet 回显:
"Hello, juneau!"
4.3 内容协商与媒体类型(实测 9.2.0 支持清单)
BasicRestServlet 默认挂载全部序列化器。请求 Accept: application/xml 返回 406,报错正文回显完整支持类型表:
HTTP 406: Not Acceptable
Unsupported media-type in request header 'Accept': 'application/xml'
Supported media-types: ['text/html','text/html+stripped','application/json','text/json','application/json5','text/json5','application/json+schema','text/json+schema','text/xml','text/uon','application/x-www-form-urlencoded','text/openapi','octal/msgpack','text/xml+soap','text/plain','text/csv']
要点:XML 是 text/xml;URL-ENC 对应 application/x-www-form-urlencoded;MsgPack 是 octal/msgpack;不带 Accept 头(*/*)默认走 text/html 页面包装。
4.4 RestClient 客户端参数(实测)
juneau-rest-client 的 RestClient.create() Builder:
.json()——注册 JSON 解析器,响应getContent().as(Pet.class)才能工作(实测未注册时抛Unsupported media-type in request header 'Content-Type': 'application/json');.accept("application/json")——请求头 Accept,驱动服务端内容协商;.run()——同步执行,返回RestResponse;RestResponse.getStatusCode()/getContentType()——状态码与响应类型;.assertStatus(200)/.assertContent(...)——断言链(实测断言失败抛异常,断言通过返回 RestResponse)。
实测回显(节选):
=== [2] GET 响应直接反序列化为 Pet ===
id=1001 name=beibei tags=[golden, young] status=PENDING
=== [3] POST 提交 POJO(自动序列化) ===
状态码=200
{"id":2003,"name":"duoduo","price":1099.0,"status":"PENDING","tags":["border collie"]}
=== [5] 断言式校验(assertStatus/assertContent) ===
断言通过, 状态码=200
⚠️
assertContent比较的是响应原文:Accept: application/json下 String 返回值会被 JSON 引号包裹(实测"Hello from Apache Juneau 9.2.0 REST"带引号),断言期望值需一致。
五、微服务配置参数(juneau-microservice-jetty)
5.1 demo.cfg 的 [Jetty] 段(实测)
| 参数 | 类型 | 默认 | 说明 | 实测 |
|---|---|---|---|---|
port | int | — | 监听端口,写入系统属性 availablePort 供 jetty.xml 引用 | ✔ port = 10000 → Started oejs.ServerConnector ... {0.0.0.0:10000} |
resolveVars | boolean | false | jetty.xml 中 $S{...} 变量解析开关 | ✔ 缺失时报 NumberFormatException: For input string: "$S{availablePort,10000}" |
maxThreads | int | 200 | Jetty 线程池上限 | ✔ 同步设置进 jetty.xml 线程池 |
minThreads | int | 8 | Jetty 线程池下限 | ✔ |
idleTimeout | int | 30000 | 空闲线程回收(毫秒) | ✔ |
端口回落实测:port 指定端口被占用时,服务不会失败,而是自动挑选其它可用端口(实测回落到 36265):
2026-10-11 12:51:06.297:INFO :oejs.AbstractConnector:main: Started oejs.ServerConnector@40bffbca{HTTP/1.1, (http/1.1)}{0.0.0.0:36265}
5.2 demo.cfg 的 [Logging] 段
[Logging]
logDir = logs
logFile = juneau-rest_%G_%M-%N.log
level = INFO
%G/%M/%N 为日期/分钟/序号占位;logDir 同时被 jetty.xml 的请求日志引用($S{Logging/logDir,logs})。
5.3 jetty.xml 关键配置
- 端口:
<Set name="port">$S{availablePort,10000}</Set>,变量值来自[Jetty]/port; - 线程池:
minThreads/maxThreads/idleTimeout; - 请求日志:
CustomRequestLog+RequestLogWriter,输出到$S{Logging/logDir,logs}/jetty-requests.log,保留 90 天(retainDays)。
实测访问日志行:
127.0.0.1 - - [11/Oct/2026:12:53:09 +0000] "GET /hello HTTP/1.1" 200 37 "" "curl/7.81.0"
5.4 JVM 启动参数(实测)
java -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -jar target/juneau-rest-1.0.0.jar --cfg=/opt/juneau-rest/demo.cfg
- 堆内存限定 256–512MB;
-Dfile.encoding=UTF-8保证中文正常;--cfg=指定配置文件路径(缺省时按<jar名>.cfg在工作目录查找)。
实测堆参数生效验证(jps -v):
8846 juneau-rest-1.0.0.jar -Xms256m -Xmx512m -Dfile.encoding=UTF-8
六、生产参数模板
可直接复制的最小生产模板(与实测工程一致):
demo.cfg:
# =============================================================================
# Juneau 微服务演示配置文件
# =============================================================================
[Logging]
logDir = logs
logFile = juneau-rest_%G_%M-%N.log
level = INFO
[Jetty]
port = 10000
resolveVars = true
maxThreads = 100
minThreads = 10
idleTimeout = 60000
jetty.xml 线程池段(完整文件见安装指南 4.8):
<Get name="ThreadPool">
<Set name="minThreads" type="int">10</Set>
<Set name="maxThreads" type="int">100</Set>
<Set name="idleTimeout" type="int">60000</Set>
<Set name="detailedDump">true</Set>
</Get>
启动命令(nohup 或 systemd ExecStart,堆 256–512MB):
nohup java -Xms256m -Xmx512m -Dfile.encoding=UTF-8 \
-jar target/juneau-rest-1.0.0.jar --cfg=/opt/juneau-rest/demo.cfg > /tmp/rest-run.log 2>&1 &
systemd 单元(/etc/systemd/system/juneau-rest.service):
[Service]
Type=simple
User=root
WorkingDirectory=/opt/juneau-rest
ExecStart=/usr/bin/java -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -jar /opt/juneau-rest/target/juneau-rest-1.0.0.jar --cfg=/opt/juneau-rest/demo.cfg
Restart=on-failure
RestartSec=5
序列化器选型速查(均为 9.2.0 实测可用):
JsonSerializer.create().ws().build() // JSON 可读格式
JsonSerializer.create().sq().build() // JSON 单引号紧凑
XmlSerializer.create().ns().ws().build() // XML 命名空间
HtmlSerializer.create().ws().build() // HTML 表格
UonSerializer.create().build() // UON
UrlEncodingSerializer.create().build() // URL 编码
SoapXmlSerializer.create().build() // SOAP XML
JsonParser.create().build() // JSON 解析
XmlParser.create().build() // XML 解析
七、常见问题(FAQ)
Q1:Accept: application/xml 返回 406?
9.2.0 的 XML 媒体类型是 text/xml,改 Accept 即可,支持类型表见 4.3。
Q2:启动报 NumberFormatException: For input string: "$S{availablePort,10000}"?
[Jetty] 段缺 resolveVars = true,补上重启(实测修复)。
Q3:配置了 port = 10000 却监听在其它端口?
端口被占时 Juneau 自动挑可用端口(实测 36265),以启动日志 Started oejs.ServerConnector ... {0.0.0.0:端口} 为准。
Q4:解析 JSON 报 Unknown property 'xxx' encountered?
未知属性默认严格报错,加 ignoreUnknownBeanProperties() 或对齐字段(见 2.2 实测)。
Q5:@Bean(properties={"id"}) 编译不过?
9.2.0 的 properties 是 String 类型,写 @Bean(properties="id")(逗号分隔多属性)。
Q6:响应对象的 _type 字段怎么打开?
序列化器加 addRootType()(根对象)或 addBeanTypes()(集合内对象),Bean 需带 @Bean(typeName="Pet"),实测见 2.1。
Q7:9.2.0 里找不到 bpi()/trimStrings()/keepNullProperties()?
这些参数已在 9.2.0 移除(实测 javap),属性白名单改用 @Bean(properties=...)。
Q8:POST 请求体参数注解用哪个?
9.2.0 用 @Content(旧版 @Body 已删除,实测 import org.apache.juneau.http.annotation.Content)。
八、参考链接
- Juneau 官方文档(Config 与 BeanContext):https://juneau.apache.org/docs/topics/
- juneau-microservice-jetty Basics:https://juneau.apache.org/docs/topics/JuneauMicroserviceJettyBasics
- Maven Central:juneau-marshall 9.2.0(https://repo1.maven.org/maven2/org/apache/juneau/juneau-marshall/9.2.0/)
- Maven Central:juneau-microservice-jetty 9.2.0(https://repo1.maven.org/maven2/org/apache/juneau/juneau-microservice-jetty/9.2.0/)