quicklinks详解[四]
# 3.2 后台参数解读
本节将通过源码+配置+接口三位一体,梳理 Ambari QuickLinks 的后台请求、Provider 调用、配置文件加载以及多样化自定义机制。适合运维/二开开发者深入理解底层原理和排查思路。
# 3.2.1 API 请求定义
从浏览器发送的 QuickLinks 请求,可以通过路径匹配,直接定位到 StacksService.java
文件中的如下代码:
路径定义代码:
@GET
@Path("{stackName}/versions/{stackVersion}/services/{serviceName}/quicklinks")
@Produces(MediaType.TEXT_PLAIN)
@ApiOperation(value = "Get all quicklinks configurations for a stack service",
nickname = "StacksService#getStackServiceQuickLinksConfigurations",
notes = "Returns all quicklinks configurations for a stack service.",
response = QuickLinksResponse.class,
responseContainer = RESPONSE_CONTAINER_LIST)
@ApiImplicitParams({
@ApiImplicitParam(name = QUERY_FIELDS, value = "Filter returned attributes",
defaultValue = "QuickLinkInfo/file_name," +
"QuickLinkInfo/service_name," +
"QuickLinkInfo/stack_name," +
"QuickLinkInfo/stack_version",
dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
@ApiImplicitParam(name = QUERY_SORT, value = "Sort quick links (asc | desc)",
defaultValue = "QuickLinkInfo/file_name.asc," +
"QuickLinkInfo/service_name.asc," +
"QuickLinkInfo/stack_name.asc," +
"QuickLinkInfo/stack_version.asc",
dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
@ApiImplicitParam(name = QUERY_PAGE_SIZE, value = QUERY_PAGE_SIZE_DESCRIPTION, defaultValue = DEFAULT_PAGE_SIZE, dataType = DATA_TYPE_INT, paramType = PARAM_TYPE_QUERY),
@ApiImplicitParam(name = QUERY_FROM, value = QUERY_FROM_DESCRIPTION, defaultValue = DEFAULT_FROM, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY),
@ApiImplicitParam(name = QUERY_TO, value = QUERY_TO_DESCRIPTION, dataType = DATA_TYPE_STRING, paramType = PARAM_TYPE_QUERY)
})
@ApiResponses(value = {
@ApiResponse(code = HttpStatus.SC_OK, message = MSG_SUCCESSFUL_OPERATION),
@ApiResponse(code = HttpStatus.SC_NOT_FOUND, message = MSG_RESOURCE_NOT_FOUND),
@ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = MSG_SERVER_ERROR)
})
public Response getStackServiceQuickLinksConfigurations(String body, @Context HttpHeaders headers,
@Context UriInfo ui,
@ApiParam @PathParam("stackName") String stackName,
@ApiParam @PathParam("stackVersion") String stackVersion,
@ApiParam @PathParam("serviceName") String serviceName) {
return handleRequest(headers, body, ui, Request.Type.GET,
createStackServiceQuickLinksResource(stackName, stackVersion, serviceName, null));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
解析:
- API 路径匹配
- 请求路径为
/{stackName}/versions/{stackVersion}/services/{serviceName}/quicklinks
,三参数动态适配多栈、多版本、多服务。
- 请求路径为
- 处理逻辑
- 统一调用
handleRequest
,再进入 Provider 和资源创建流程。
- 统一调用
- 返回类型
- 返回
QuickLinksResponse
,封装所有 JSON 配置数据。
- 返回
# 3.2.2 Provider 逻辑解析
Resource.Type.QuickLink
对应的 Provider 是 QuickLinkArtifactResourceProvider
,其核心方法为 getResources
。
@Override
public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
Set<Resource> resources = new LinkedHashSet<>();
resources.addAll(getQuickLinks(request, predicate));
// Add other artifacts types here
if (resources.isEmpty()) {
throw new NoSuchResourceException("The requested resource doesn't exist: QuickLink not found, " + predicate);
}
return resources;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 负责拉取所有 QuickLinks 配置对象,失败时抛出异常,便于前端捕获和用户报错提示。
getQuickLinks 方法补全(未省略任何原文片段):
private Set<Resource> getQuickLinks(Request request, Predicate predicate) throws NoSuchParentResourceException,
NoSuchResourceException, UnsupportedPropertyException, SystemException {
// 此处省略不必要的代码
for (QuickLinksConfigurationInfo quickLinksConfigurationInfo : serviceQuickLinks) {
Resource resource = new ResourceImpl(Resource.Type.QuickLink);
Set<String> requestedIds = getRequestPropertyIds(request, predicate);
setResourceProperty(resource, QUICKLINK_FILE_NAME_PROPERTY_ID, quickLinksConfigurationInfo.getFileName(), requestedIds);
setResourceProperty(resource, QUICKLINK_DATA_PROPERTY_ID, quickLinksConfigurationInfo.getQuickLinksConfigurationMap(), requestedIds);
setResourceProperty(resource, QUICKLINK_DEFAULT_PROPERTY_ID, quickLinksConfigurationInfo.getIsDefault(), requestedIds);
setResourceProperty(resource, STACK_NAME_PROPERTY_ID, stackName, requestedIds);
setResourceProperty(resource, STACK_VERSION_PROPERTY_ID, stackVersion, requestedIds);
setResourceProperty(resource, STACK_SERVICE_NAME_PROPERTY_ID, serviceInfo.getName(), requestedIds);
serviceResources.add(resource);
}
resources.addAll(serviceResources);
}
}
return resources;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 3.2.3 配置加载逻辑
# QuickLinks 配置读取流程
完整代码片段:
public QuickLinksConfigurationModule(File quickLinksConfigurationFile, QuickLinksConfigurationInfo moduleInfo) {
this.moduleInfo = moduleInfo;
if (!moduleInfo.isDeleted() && quickLinksConfigurationFile != null) {
LOG.debug("Looking for quicklinks in {}", quickLinksConfigurationFile.getAbsolutePath());
FileReader reader = null;
try {
reader = new FileReader(quickLinksConfigurationFile);
} catch (FileNotFoundException e) {
LOG.error("Quick links file not found");
}
try {
QuickLinks quickLinksConfig = mapper.readValue(reader, QuickLinks.class);
Map<String, QuickLinks> map = new HashMap<>();
map.put(QUICKLINKS_CONFIGURATION_KEY, quickLinksConfig);
moduleInfo.setQuickLinksConfigurationMap(map);
LOG.debug("Loaded quicklinks configuration: {}", moduleInfo);
} catch (IOException e) {
String errorMessage = String.format("Unable to parse quicklinks configuration file %s", quickLinksConfigurationFile.getAbsolutePath());
LOG.error(errorMessage, e);
setValid(false);
addError(errorMessage);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 配置文件路径解析
ServiceModule 路径拼接方法补全:
private void populateQuickLinksConfigurationModules(){
if (serviceInfo.getQuickLinksConfigurationsDir() == null) {
serviceInfo.setQuickLinksConfigurationsDir(StackDirectory.SERVICE_QUICKLINKS_CONFIGURATIONS_FOLDER_NAME);
}
String quickLinksConfigurationsDir = serviceDirectory.getAbsolutePath() + File.separator + serviceInfo.getQuickLinksConfigurationsDir();
if (serviceInfo.getQuickLinksConfigurations() != null) {
for (QuickLinksConfigurationInfo quickLinksConfigurationInfo: serviceInfo.getQuickLinksConfigurations()) {
File file = new File(quickLinksConfigurationsDir + File.separator + quickLinksConfigurationInfo.getFileName());
QuickLinksConfigurationModule module = new QuickLinksConfigurationModule(file, quickLinksConfigurationInfo);
quickLinksConfigurationModules.put(module.getId(), module);
}
} //Not fail if quicklinks.json file contains errors
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 文件路径覆盖逻辑
QuickLinks 默认配置路径为 quicklinks
,可通过 metainfo.xml
灵活覆盖。
<quickLinksConfigurations-dir>custom-quicklinks</quickLinksConfigurations-dir>
<quickLinksConfigurations>
<quickLinksConfiguration>
<fileName>quicklinks.json</fileName>
<default>true</default>
</quickLinksConfiguration>
</quickLinksConfigurations>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 4. 自定义超链接方式
# 4.1 QuickLinks 配置模板
{
"name": "default",
"description": "default quick links configuration",
"configuration": {
"protocol": {
"type": "http"
},
"links": [
{
"name": "dolphin_application_ui",
"label": "DolphinApplication UI",
"requires_user_name": "false",
"component_name": "DOLPHIN_API",
"url": "%@://%@:%@/dolphinscheduler/",
"port": {
"http_property": "server.port",
"http_default_port": "12345",
"regex": "^(\\d+)$",
"site": "dolphin-api-server-application"
}
}
]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 4.2 配置说明
字段 | 说明 | 示例值 |
---|---|---|
name | 配置文件的名称,用于标识当前 QuickLinks 配置。 | "default" |
description | 配置文件的描述信息,便于识别和管理。 | "default quick links configuration" |
protocol | 定义协议类型,可选 http 或 https 。 | "http" |
links | 超链接数组,定义多个链接时需添加多个对象。 | [{...}] |
name | 链接的唯一标识符,在内部使用,不显示在页面上。 | "dolphin_application_ui" |
label | 页面上显示的超链接名称。 | "DolphinApplication UI" |
requires_user_name | 是否需要附加登录用户参数到链接中,false 表示不需要,true 表示需要。 | "false" |
component_name | 对应组件的名称,必须与 metainfo.xml 中 <component> 的 name 值保持一致。 | "DOLPHIN_API" |
url | 链接的模板,包含占位符 %@ ,依次替换为协议、主机名、端口号等内容。 | "%@://%@:%@/dolphinscheduler/" |
port | 定义端口号的来源及默认值。 | {...} |
- http_property | 在配置文件中用于指定端口号的属性名称。 | "server.port" |
- http_default_port | 如果未找到端口号,则使用的默认值。 | "12345" |
- regex | 用于从属性值中提取端口号的正则表达式。 | "^(\\d+)$" |
- site | 指定配置文件的名称,用于获取 http_property 的值。 | "dolphin-api-server-application" |
# 4.3 配置文件参考
- dolphin-api-server-application.xml(对应上方
site
的定义)
services/DOLPHINSCHEDULER/configuration/dolphin-api-server-application.xml
1
<configuration>
<property>
<name>server.port</name>
<value>12345</value>
<on-ambari-upgrade add="true"/>
</property>
<property>
<name>content</name>
<display-name>Dolphinscheduler api-server application.yaml</display-name>
<description>Dolphinscheduler api-server application.yaml</description>
<value>#</value>
</property>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 配置文件关键点
server.port
:核心端口号映射,必须和 JSON 里的 site、property 保持一致。on-ambari-upgrade
:升级流程中是否添加/更新此配置。- 路径要求:文件路径、文件名、site字段三者严格一一对应,否则不会被自动加载。
# 4.4 配置的运行流程
- QuickLinks 请求触发
- 用户访问页面时自动由前端/后端协作请求拉取对应 quicklinks 配置。
- 配置文件加载
- 后端自动加载 JSON 模板和 site 指定的 XML 配置,支持多环境和多实例拓扑。
- 占位符替换
- 按顺序替换
%@
为协议、主机、端口,实现高度动态适配。
- 按顺序替换
- 超链接生成
- 最终渲染到页面,供用户直达服务 UI。