java 请求过程解读[三]
# 3.6 Provider 解读
在 3.5 ClusterController 解读 中,我们已经了解到 ClusterController
如何通过查找和调用资源提供者(ResourceProvider
)来驱动整个查询链路。本节我们聚焦于资源提供者(Provider)体系的实现细节与工作流,包括它们的分层结构、实例化机制、查询分发和实际数据的获取。你将看到
Ambari 如何用统一的 Provider 体系高效适配不同的资源类型,并通过工厂和缓存模式实现极强的扩展性和灵活性。
提示
如上图所示,Provider 层通过 ProviderModule 管理,DefaultProviderModule 是核心工厂,针对不同资源类型返回对应 ResourceProvider 实例(如 StackServiceResourceProvider、JobResourceProvider 等),支撑了整个资源查询能力。
# 3.6.1 Provider 之间的分层与协作
Ambari 所有资源提供者(ResourceProvider)都继承自 AbstractProviderModule
,统一了资源管理接口与缓存逻辑。
而 DefaultProviderModule
是它的标准实现,负责实际的 Provider 实例化与注册。两者关系如下:
AbstractProviderModule
- 抽象类,定义了 Provider
的通用接口与注册、查找、缓存机制(如
getResourceProvider
、registerResourceProvider
、createResourceProvider
等)。
- 抽象类,定义了 Provider
的通用接口与注册、查找、缓存机制(如
DefaultProviderModule
- 继承自
AbstractProviderModule
,实现了createResourceProvider
,根据资源类型工厂化创建并返回对应 Provider。
- 继承自
核心代码与逻辑:
@Override
public ResourceProvider getResourceProvider(Resource.Type type) {
if (!resourceProviders.containsKey(type)) {
registerResourceProvider(type); // 未注册则自动注册
}
return resourceProviders.get(type); // 缓存命中直接返回
}
2
3
4
5
6
7
笔记
通过 Provider 层的缓存机制,Ambari 避免了重复构建 Provider,极大提升了查询性能与资源复用。
# 3.6.2 Provider 注册与工厂分发
createResourceProvider
:由子类实现,针对不同资源类型返回具体 Provider 实例。registerResourceProvider
:自动注册新 Provider 到缓存,并为支持监听的 Provider 自动绑定观察者模式。
protected abstract ResourceProvider createResourceProvider(Resource.Type type);
protected void registerResourceProvider(Resource.Type type) {
ResourceProvider resourceProvider = createResourceProvider(type);
if (resourceProvider instanceof ObservableResourceProvider) {
((ObservableResourceProvider) resourceProvider).addObserver(this); // 自动监听变更
}
putResourceProvider(type, resourceProvider);
}
2
3
4
5
6
7
8
9
10
每种资源类型(如 StackService、Job、Workflow 等)都有专属 Provider 实现,DefaultProviderModule 能按需分发和注册。
# 3.6.3 Provider 的按需获取与复用
getResourceProvider
方法负责查找指定资源类型的 Provider。没有则注册新 Provider,有则复用缓存。
public ResourceProvider getResourceProvider(Resource.Type type) {
if (!resourceProviders.containsKey(type)) {
registerResourceProvider(type);
}
return resourceProviders.get(type);
}
2
3
4
5
6
逻辑要点:
- 支持多资源类型(每种类型单独缓存,避免并发创建冲突)
- 注册时自动实现 Provider 的解耦和生命周期管理
# 3.6.4 DefaultProviderModule 的分发实现
在 DefaultProviderModule
中,不同资源类型会分发到不同的 Provider 实例:
@Override
protected ResourceProvider createResourceProvider(Resource.Type type) {
LOGGER.debug("Creating resource provider for the type: {}", type);
switch (type.getInternalType()) {
case Workflow:
return new WorkflowResourceProvider();
case Job:
return new JobResourceProvider();
case TaskAttempt:
return new TaskAttemptResourceProvider();
// 其他资源类型...
default:
LOGGER.debug("Delegating creation of resource provider for: {} to the AbstractControllerResourceProvider", type.getInternalType());
return AbstractControllerResourceProvider.getResourceProvider(type, managementController);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
逻辑要点:
- 大部分常见类型(如 Workflow、Job 等)专门 Provider 直连
- 默认走通用的 ControllerResourceProvider,适配未知或扩展类型
这种实现允许自定义资源类型 Provider解耦与扩展性,满足未来扩展和第三方插件对接需求。
# 3.6.5 Provider 查询主流程:getResources
每个 Provider 必须实现自己的 getResources
方法,负责根据请求条件返回实际的数据集合。以 StackServiceResourceProvider
为例:
@Override
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
final Set<StackServiceRequest> requests = new HashSet<>();
if (predicate == null) {
requests.add(getRequest(Collections.emptyMap()));
} else {
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
requests.add(getRequest(propertyMap));
}
}
Set<StackServiceResponse> responses = getResources(new Command<Set<StackServiceResponse>>() {
@Override
public Set<StackServiceResponse> invoke() throws AmbariException {
return getManagementController().getStackServices(requests);
}
});
Set<Resource> resources = new HashSet<>();
for (StackServiceResponse response : responses) {
Resource resource = createResource(response, requestedIds);
resources.add(resource);
}
return resources;
}
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
- 构建查询:先将请求/条件转化为标准化的 requests。
- 实际执行:调用 managementController 的 getStackServices(或同类方法)真正去查询业务数据。
- 封装返回:用 createResource 封装结果,统一数据格式后返回。
# 4. 最佳实践与技巧 💡
在 Ambari 项目中,规范的命名和工厂分发机制极大提升了源码的可读性和可维护性。以下技巧和习惯可以帮你更快定位和理解 Provider 的实现:
# 4.1 通过 Resource.Type.<Xxx>
快速定位
每种资源类型(如 StackService、Cluster、Host 等)都有固定的命名规范:
- 资源定义:如
StackServiceResourceDefinition
- 资源提供者:如
StackServiceResourceProvider
- 资源定义:如
只要知道 Resource.Type,就可以一键全局搜索到对应的 ResourceDefinition/ResourceProvider 源码。
提示
配合 IDE 的类跳转、正则搜索与类型全局定位,可以显著提高定位和理解复杂 Provider 的效率。
# 5. 总结与延伸学习 🚀
# 5.1 内容回顾
本文详细讲解了 Provider 层在 Ambari 服务查询流程中的关键作用,包含:
- Provider 层次结构:分层抽象与 DefaultProviderModule 工厂实现,带来良好的扩展性与解耦。
- Provider 创建与分发机制:缓存与注册、自动类型分发、可插拔扩展。
- getResources 查询链路:统一规范的数据查询和结果封装。
- 命名规则和快速定位技巧:助你高效扩展、维护和定制 Ambari 查询能力。
通过本节内容,你可以轻松理解 Ambari 查询处理的对象流转链条,快速定位 Provider 实现,掌握二次开发和问题定位的核心工具。