TT Bigdata TT Bigdata
首页
  • 部署专题

    • 常规安装
    • 一键部署
  • 组件安装

    • 常规&高可用
  • 版本专题

    • 更新说明
  • Ambari-Env

    • 环境准备
    • 开始使用
  • 组件编译

    • 专区—Ambari
    • 专区—Bigtop
  • 报错解决

    • 专区—Ambari
    • 专区—Bigtop
  • 其他技巧

    • Maven镜像加速
    • Gradle镜像加速
    • Bower镜像加速
    • 虚拟环境思路
    • R环境安装+一键安装脚本
    • Ivy配置私有镜像仓库
    • Node.js 多版本共存方案
    • Ambari Web本地启动
    • Npm镜像加速
    • PostgreSQL快速安装
    • Temurin JDK 23快速安装
  • 成神之路

    • 专区—Ambari
    • 专区—Bigtop
  • 集成案例

    • Redis集成教学
    • Dolphin集成教学
    • Doris集成教学
    • 持续整理...
  • 模板代码

    • 各类组件
    • 通用模板
  • 国产化&其他系统

    • Centos系列
    • Kylin系列
    • OpenEuler系列
    • Rocky系列
    • Ubuntu系列
  • 生产调优

    • 组件调优指南
    • 1v1指导调优
  • 定制开发

    • 组件版本定制
    • 样式风格定制
  • 蓝图愿景
  • 技术支持
  • 合作共建
GitHub (opens new window)

JaneTTR

数据酿造智慧,每一滴都是沉淀!
首页
  • 部署专题

    • 常规安装
    • 一键部署
  • 组件安装

    • 常规&高可用
  • 版本专题

    • 更新说明
  • Ambari-Env

    • 环境准备
    • 开始使用
  • 组件编译

    • 专区—Ambari
    • 专区—Bigtop
  • 报错解决

    • 专区—Ambari
    • 专区—Bigtop
  • 其他技巧

    • Maven镜像加速
    • Gradle镜像加速
    • Bower镜像加速
    • 虚拟环境思路
    • R环境安装+一键安装脚本
    • Ivy配置私有镜像仓库
    • Node.js 多版本共存方案
    • Ambari Web本地启动
    • Npm镜像加速
    • PostgreSQL快速安装
    • Temurin JDK 23快速安装
  • 成神之路

    • 专区—Ambari
    • 专区—Bigtop
  • 集成案例

    • Redis集成教学
    • Dolphin集成教学
    • Doris集成教学
    • 持续整理...
  • 模板代码

    • 各类组件
    • 通用模板
  • 国产化&其他系统

    • Centos系列
    • Kylin系列
    • OpenEuler系列
    • Rocky系列
    • Ubuntu系列
  • 生产调优

    • 组件调优指南
    • 1v1指导调优
  • 定制开发

    • 组件版本定制
    • 样式风格定制
  • 蓝图愿景
  • 技术支持
  • 合作共建
GitHub (opens new window)
  • 方法论

  • 代码生命周期-metainfo

    • 加载原理深度剖析[一]
    • 加载原理深度剖析[二]
      • 2. Ambari 如何解析 metainfo.xml?
        • 2.1 核心解析流程 🛠️
        • parseDirectories() 方法
        • 2.2 StackModule 类中的初始化 🧩
        • populateStackInfo() 方法
        • 2.3 服务与组件的逐层解析 🔍
        • populateServices() 方法
        • populateService() 详细逻辑
    • 加载原理深度剖析[三]
    • 结构与层级深入解读
    • configFile详解[一]
    • configFile详解[二]
    • cardinality详解[一]
    • cardinality详解[二]
    • cardinality详解[三]
    • category详解[一]
    • category详解[二]
    • category详解[三]
    • theme详解[一]
    • theme详解[二]
    • theme详解[三]
    • commandScript详解[二]
    • commandScript详解[一]
    • commandScript详解[三]
    • customCommand详解[一]
    • customCommand详解[二]
    • customCommand详解[三]
    • requiredServices详解[一]
    • requiredServices详解[二]
    • osSpecifics详解[一]
    • osSpecifics详解[二]
    • osSpecifics详解[三]
    • quicklinks详解[一]
    • quicklinks详解[二]
    • quicklinks详解[三]
    • quicklinks详解[四]
  • 架构剖析

  • UI样式

  • GOD-Ambari
  • 代码生命周期-metainfo
JaneTTR
2025-05-31
目录

加载原理深度剖析[二]

在 Ambari 的服务集成体系中,metainfo.xml 的解析是服务自动发现、组件注册与运维编排的第一步。下面结合源码,系统梳理 Ambari 是如何完成 metainfo.xml 的加载与结构化解析的。

# 2. Ambari 如何解析 metainfo.xml?

Ambari 的 Stack 管理模块,主要依赖 StackManager 和 StackModule 两大核心类。它们将 Stack 目录下的元数据、服务与组件信息,逐步解析为 Java 对象,贯穿服务的整个生命周期管理。

# 2.1 核心解析流程 🛠️

Stack 解析的主入口是 StackManager 构造方法。它负责递归遍历 Stack 根目录,依次解析服务、组件及其依赖。

image-20240922115207320

 @AssistedInject
  public StackManager(@Assisted("stackRoot") File stackRoot,
      @Assisted("commonServicesRoot") @Nullable File commonServicesRoot,
      @Assisted("extensionRoot") @Nullable File extensionRoot,
      @Assisted OsFamily osFamily, @Assisted boolean validate,
      MetainfoDAO metaInfoDAO, ActionMetadata actionMetadata, StackDAO stackDao,
      ExtensionDAO extensionDao, ExtensionLinkDAO linkDao, AmbariManagementHelper helper)
      throws AmbariException {

    LOG.info("Initializing the stack manager...");

    if (validate) {
      validateStackDirectory(stackRoot);
      validateCommonServicesDirectory(commonServicesRoot);
      validateExtensionDirectory(extensionRoot);
    }

    stackMap = new TreeMap<>();
    stackContext = new StackContext(metaInfoDAO, actionMetadata, osFamily);
    extensionMap = new HashMap<>();
    this.helper = helper;
    
    // 初始化并解析目录-------核心中的核心 请往这里看👀
     // 初始化并解析目录-------核心中的核心 请往这里看👀
    parseDirectories(stackRoot, commonServicesRoot, extensionRoot);
 		// 初始化并解析目录-------核心中的核心 请往这里看👀
    // 初始化并解析目录-------核心中的核心 请往这里看👀
    
    //Read the extension links from the DB
    for (StackModule module : stackModules.values()) {
      StackInfo stack = module.getModuleInfo();
      List<ExtensionLinkEntity> entities = linkDao.findByStack(stack.getName(), stack.getVersion());
      for (ExtensionLinkEntity entity : entities) {
        String name = entity.getExtension().getExtensionName();
        String version = entity.getExtension().getExtensionVersion();
        String key = name + StackManager.PATH_DELIMITER + version;
        ExtensionModule extensionModule = extensionModules.get(key);
        if (extensionModule != null) {
          LOG.info("Adding extension to stack/version: " + stack.getName() + "/" + stack.getVersion() +
                   " extension/version: " + name + "/" + version);
          //Add the extension to the stack
          module.getExtensionModules().put(key, extensionModule);
        }
      }
    }

    fullyResolveCommonServices(stackModules, commonServiceModules, extensionModules);
    fullyResolveExtensions(stackModules, commonServiceModules, extensionModules);
    fullyResolveStacks(stackModules, commonServiceModules, extensionModules);

    populateDB(stackDao, extensionDao);
  }
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
40
41
42
43
44
45
46
47
48
49
50
51
52

构造函数中 parseDirectories() 方法递归解析 Stack、Common Services 和 Extension 目录,逐步加载关键点所有 metainfo.xml 文件。

# parseDirectories() 方法

protected void parseDirectories(File stackRoot, File commonServicesRoot, File extensionRoot) throws AmbariException {
    // 解析通用服务目录
    commonServiceModules = parseCommonServicesDirectory(commonServicesRoot);
    // 解析堆栈目录-------核心中的核心 请往这里看👀
  	// 解析堆栈目录-------核心中的核心 请往这里看👀
    stackModules = parseStackDirectory(stackRoot);
 	 // 解析堆栈目录-------核心中的核心 请往这里看👀
 	 // 解析堆栈目录-------核心中的核心 请往这里看👀
    LOG.info("About to parse extension directories");
    // 解析扩展目录
    extensionModules = parseExtensionDirectory(extensionRoot);
  }
1
2
3
4
5
6
7
8
9
10
11
12

其中 parseStackDirectory(stackRoot) 是核心,递归查找每个 Stack 版本目录,加载 metainfo.xml 并注册服务:

private Map<String, StackModule> parseStackDirectory(File stackRoot) throws AmbariException {
    Map<String, StackModule> stackModules = new HashMap<>();

    File[] stackFiles = stackRoot.listFiles(StackDirectory.FILENAME_FILTER);
    for (File stack : stackFiles) {
        if (stack.isFile()) {
            continue;
        }

        for (File stackFolder : stack.listFiles(StackDirectory.FILENAME_FILTER)) {
            if (stackFolder.isFile()) {
                continue;
            }

            String stackName = stackFolder.getParentFile().getName();
            String stackVersion = stackFolder.getName();
						// 解析堆栈目录-------核心中的核心 请往这里看👀
          	// 解析堆栈目录-------核心中的核心 请往这里看👀
            StackModule stackModule = new StackModule(new StackDirectory(stackFolder.getPath()), stackContext);
            // 解析堆栈目录-------核心中的核心 请往这里看👀
            // 解析堆栈目录-------核心中的核心 请往这里看👀
            String stackKey = stackName + StackManager.PATH_DELIMITER + stackVersion;
            stackModules.put(stackKey, stackModule);
            stackMap.put(stackKey, stackModule.getModuleInfo());
        }
    }

    if (stackMap.isEmpty()) {
        throw new AmbariException("Unable to find stack definitions under stackRoot = " + stackRoot.getAbsolutePath());
    }

    return stackModules;
}

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

笔记

每一个 Stack 目录下都会实例化一个 StackModule,对应于每个 metainfo.xml 文件的解析对象。

# 2.2 StackModule 类中的初始化 🧩

每个 StackModule 代表一个 Stack 版本,它的初始化会自动加载并解析 metainfo.xml:

image-20240922120854436

public StackModule(StackDirectory stackDirectory, StackContext stackContext) {
    this.stackDirectory = stackDirectory;
    this.stackContext = stackContext;
    stackInfo = new StackInfo();
    populateStackInfo();  // 解析 metainfo.xml
}
1
2
3
4
5
6

# populateStackInfo() 方法

核心逻辑就是通过 stackDirectory.getMetaInfoFile() 获取 metainfo.xml 的 XML 映射对象,再转化为 StackInfo:

StackMetainfoXml smx = stackDirectory.getMetaInfoFile();
if (smx != null) {
    if (!smx.isValid()) {
        stackInfo.setValid(false);
        stackInfo.addErrors(smx.getErrors());
    }
    stackInfo.setMinJdk(smx.getMinJdk());
    stackInfo.setMaxJdk(smx.getMaxJdk());
    stackInfo.setActive(smx.getVersion().isActive());
    stackInfo.setParentStackVersion(smx.getExtends());
}
1
2
3
4
5
6
7
8
9
10
11

提示

这一步会把 metainfo.xml 的 JDK 依赖、Stack 继承、启用状态等基础信息都映射到 StackInfo 实例中。

# 2.3 服务与组件的逐层解析 🔍

# populateServices() 方法

服务和组件的注册与解析,是通过遍历 Service 目录、调用 populateService() 方法实现的:

private void populateServices() throws AmbariException {
    for (ServiceDirectory serviceDir : stackDirectory.getServiceDirectories()) {
        populateService(serviceDir);  // 调用子服务解析
    }
}
1
2
3
4
5

# populateService() 详细逻辑

populateService() 用于把 metainfo.xml 中的每个服务,注册为 ServiceModule 对象:

private void populateService(ServiceDirectory serviceDirectory) {
        Collection<ServiceModule> serviceModules = new ArrayList<>();
        // unfortunately, we allow multiple services to be specified in the same metainfo.xml,
        // so we can't move the unmarshal logic into ServiceModule
        ServiceMetainfoXml metaInfoXml = serviceDirectory.getMetaInfoFile();
        if (!metaInfoXml.isValid()) {
            stackInfo.setValid(metaInfoXml.isValid());
            setValid(metaInfoXml.isValid());
            stackInfo.addErrors(metaInfoXml.getErrors());
            addErrors(metaInfoXml.getErrors());
            return;
        }
        List<ServiceInfo> serviceInfos = metaInfoXml.getServices();

        for (ServiceInfo serviceInfo : serviceInfos) {
            // 初始化并解析Service-------核心中的核心 请往这里看👀
          	// 初始化并解析Service-------核心中的核心 请往这里看👀
            ServiceModule serviceModule = new ServiceModule(stackContext, serviceInfo, serviceDirectory);
            // 初始化并解析Service-------核心中的核心 请往这里看👀
            // 初始化并解析Service-------核心中的核心 请往这里看👀
            serviceModules.add(serviceModule);
            if (!serviceModule.isValid()) {
                stackInfo.setValid(false);
                setValid(false);
                stackInfo.addErrors(serviceModule.getErrors());
                addErrors(serviceModule.getErrors());
            }
        }
        addServices(serviceModules);
    }
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

提示

每个 ServiceModule 都包含了该服务的所有组件(Master/Slave/Client)、脚本、配置文件、健康检查等信息。

#Redis#Ambari#metainfo.xml#源码解析#服务注册
加载原理深度剖析[一]
加载原理深度剖析[三]

← 加载原理深度剖析[一] 加载原理深度剖析[三]→

最近更新
01
Pandoc 缺失导致 SparkR 构建失败
06-08
02
Cyrus SASL/GSASL 缺失解决
06-07
03
Hadoop_3.3.4 编译实战 1.0.0+
06-06
更多文章>
Theme by Vdoing | Copyright © 2017-2025 JaneTTR | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式