Apache Juneau 配置参数详解

按层级梳理 Apache Juneau 9.2.0 序列化/解析 Builder 参数、Bean/REST 注解参数、微服务 cfg 与 jetty.xml 配置项,全部参数经真实运行实测,含生产参数模板与 FAQ。

Apache JuneauApache Juneau2026/10/12

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/@Contentpath/summary/produces/consumes/defaultCharset单个 REST 资源与方法
微服务配置demo.cfg、jetty.xml、JVM 参数Jetty/port、resolveVars、maxThreads、-Xms/-Xmx整个微服务进程

参数的权威查看方式(本文实测采用):

  1. javap 反编译 jar 查 Builder/注解的真实方法签名(9.2.0 相比旧版有增删,以字节码为准);
  2. 请求不支持的媒体类型,406 报错正文会回显全部支持媒体类型;
  3. 运行期把演示服务跑起来,用 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 请勿导错包)。属性清单:

属性类型说明实测
typeNameString字典类型名,配合 addRootType() 输出 _type✔ _type: "Pet"
typePropertyNameString_type 键名自定义—
propertiesString逗号分隔的属性白名单(注意是 String)✔ properties="id" 只输出 id
excludeProperties/xpString属性黑名单—
readOnlyProperties/roString只读属性—
writeOnlyProperties/woString只写属性—
pStringproperties 的别名—
sortboolean属性按字母序输出✔ 输出 id,name,price,soldDate,status,tags
findFluentSettersboolean识别链式 setter—
interceptorClassBeanInterceptor 拦截器—
propertyNamerClassPropertyNamer 属性重命名—
dictionaryClass[]类型字典—
implClass/interfaceClass/stopClassClass实现类/接口映射/终止类—
description/exampleString[]/String文档与示例元数据—
on/onClassString[]/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] 段(实测)

参数类型默认说明实测
portint—监听端口,写入系统属性 availablePort 供 jetty.xml 引用✔ port = 10000 → Started oejs.ServerConnector ... {0.0.0.0:10000}
resolveVarsbooleanfalsejetty.xml 中 $S{...} 变量解析开关✔ 缺失时报 NumberFormatException: For input string: "$S{availablePort,10000}"
maxThreadsint200Jetty 线程池上限✔ 同步设置进 jetty.xml 线程池
minThreadsint8Jetty 线程池下限✔
idleTimeoutint30000空闲线程回收(毫秒)✔

端口回落实测: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)。

八、参考链接