上篇分析了core plugin和service plugin的加载过程。APIRouter的构造函数下一步将进行PluginAwareExtensionManager的初始化:

ext_mgr = extensions.PluginAwareExtensionManager.get_instance()

PluginAwareExtensionManager也是一个单例模式。

class PluginAwareExtensionManager(ExtensionManager):@classmethoddef get_instance(cls):if cls._instance is None:service_plugins = directory.get_plugins()                   # 获取plugins(包括core和service)的弱引用,统称service_plugins。cls._instance = cls(get_extensions_path(service_plugins),   # 获取service_plugins支持的extensions的path。
                                service_plugins)return cls._instance

在第一次调用get_instance函数时,其_instance变量为None,进入if分支。
首先通过上一节分析的get_plugins函数获取plugins名称和弱引用对应的字典,包括core plugin和service plugin,这里统称service_plugins。
然后,实例化PluginAwareExtensionManager。这里首先调用了get_extensions_path函数:
def get_extensions_path(service_plugins=None):paths = collections.OrderedDict()# Add Neutron core extensionspaths[core_extensions.__path__[0]] = 1if service_plugins:# Add Neutron *-aas extensionsfor plugin in service_plugins.values():neutron_mod = provider_configuration.NeutronModule(plugin.__module__.split('.')[0])try:paths[neutron_mod.module().extensions.__path__[0]] = 1except AttributeError:# Occurs normally if module has no extensions sub-modulepass# Add external/other plugins extensionsif cfg.CONF.api_extensions_path:for path in cfg.CONF.api_extensions_path.split(":"):paths[path] = 1LOG.debug("get_extension_paths = %s", paths)# Re-build the extension stringpath = ':'.join(paths)return path

get_extensions_path函数构造了一个paths字典,extensions的路径为key,values均为1。这个paths包括三个部分:
  • core_extensions path:即/neutron/extensions。core_extensions保存在这个目录中;
  • Neutron *-aas extensions path:形如*-aas的extensions,例如vpnaas;
  • 配置文件中指定的其他path:配置文件中的api_extensions_path指定。
获取到extensions的path后,调用PluginAwareExtensionManager的构造函数:

class PluginAwareExtensionManager(ExtensionManager):_instance = Nonedef __init__(self, path, plugins):self.plugins = pluginssuper(PluginAwareExtensionManager, self).__init__(path)self.check_if_plugin_extensions_loaded()

可以看到,构造函数主要分为两个步骤:
  • 通过调用父类ExtensionManager的构造函数来加载extensions;
  • 检查是否所有extensions都被加载,否则抛出异常。
下面分析一下父类ExtensionManager的构造函数:
class ExtensionManager(object):"""Load extensions from the configured extension path.See tests/unit/extensions/foxinsocks.py for anexample extension implementation."""def __init__(self, path):LOG.info(_LI('Initializing extension manager.'))self.path = pathself.extensions = {}self._load_all_extensions()

ExtensionManager的构造函数调用_load_all_extensions:

class ExtensionManager(object):def _load_all_extensions(self):"""Load extensions from the configured path.The extension name is constructed from the module_name. If yourextension module is named widgets.py, the extension class within thatmodule should be 'Widgets'.See tests/unit/extensions/foxinsocks.py for an example extensionimplementation."""for path in self.path.split(':'):                   # 分别处理path中的各个extensions目录if os.path.exists(path):self._load_all_extensions_from_path(path)else:LOG.error(_LE("Extension path '%s' doesn't exist!"), path)def _load_all_extensions_from_path(self, path):# Sorting the extension list makes the order in which they# are loaded predictable across a cluster of load-balanced# Neutron Serversfor f in sorted(os.listdir(path)):                                  # 将path(extension目录)下的所有文件进行排序并遍历。try:LOG.debug('Loading extension file: %s', f)mod_name, file_ext = os.path.splitext(os.path.split(f)[-1])ext_path = os.path.join(path, f)if file_ext.lower() == '.py' and not mod_name.startswith('_'):  # 将所有.py文件(除__init__.py)作为一个extension添加到self.extensions中。mod = imp.load_source(mod_name, ext_path)ext_name = mod_name[0].upper() + mod_name[1:]               # extensions的实现类(ext_name)是对应模块名(mod_name)的首字母大写。new_ext_class = getattr(mod, ext_name, None)                # 根据ext_name到相应模块中获取extensions的实现类,没有获取到则抛出异常。if not new_ext_class:LOG.warning(_LW('Did not find expected name ''"%(ext_name)s" in %(file)s'),{'ext_name': ext_name,'file': ext_path})continuenew_ext = new_ext_class()                                   # 实例化extensions目录下各.py文件中的extensions实现类。self.add_extension(new_ext)                                 # 将各个extensions的实例添加到ExtensionManager的extensions属性中。except Exception as exception:LOG.warning(_LW("Extension file %(f)s wasn't loaded due to ""%(exception)s"),{'f': f, 'exception': exception})

可以看出,各个extension的加载就是在_load_all_extensions函数中进行的。总而言之,这个过程就是到各个extensions目录(上面已经分析过这些目录分为三个部分)中遍历每个.py文件(除了__init__.py),每个.py文件对应一个extension,该extension对应的实现类是.py文件的文件名的首字母大写。获取到各个extension的对应类后实例化,并将实例添加到PluginAwareExtensionManager.extensions变量中。
完成各个extension的加载后,在PluginAwareExtensionManager的构造函数中,还要检查是否所有extensions都被加载:

class PluginAwareExtensionManager(ExtensionManager):def check_if_plugin_extensions_loaded(self):"""Check if an extension supported by a plugin has been loaded."""plugin_extensions = self.get_supported_extension_aliases()          # 获取self.plugins中各个plugin支持的extensions,并组成set。missing_aliases = plugin_extensions - set(self.extensions)          # 取两个set的差集。missing_aliases -= _PLUGIN_AGNOSTIC_EXTENSIONS                      # 排除不依赖plugin的extension。if missing_aliases:                                                 # 如果仍有未加载的extension,则抛出异常。raise exceptions.ExtensionsNotFound(extensions=list(missing_aliases))

至此,PluginAwareExtensionManager的初始化过程就结束了。其中最重要的是PluginAwareExtensionManager中的extensions变量,这是一个保存了每个extension的实现类的实例的列表。
由于PluginAwareExtensionManager是单例模式的实现,所以之后统一通过其get_instance函数来获取这个唯一的extension manager。

转载于:https://www.cnblogs.com/Luka-Modric/p/8250442.html

Ocata Neutron代码分析(六)——APIRouter的初始化(2)PluginAwareExtensionManager的初始化...相关推荐

  1. Ocata Neutron代码分析(六)——APIRouter的初始化(1)加载core plugin和service plugin...

    在分析api-paste.ini时,曾分析到wsgi app neutronapiapp_v2_0是直接调用/neutron/api/v2/router.py中APIRouter的factory方法: ...

  2. Ocata Neutron代码分析(六)——APIRouter的初始化(3)顶级resource的map过程

    在完成了plugins和extensions的加载后,进行四个顶级resource(分别是network.subnet.subnetpool和port)的map过程.map过程指的是,将各个resou ...

  3. Ocata Neutron代码分析(一)——Neutron API启动过程分析

    首先,Neutron Server作为一种服务(neutron-server.service),可以到Neutron项目目录中的setup.cfg配置文件中找到对应的代码入口. [entry_poin ...

  4. Linux 网桥代码分析 六 网桥数据转发函数分析

    对于数据包转发函数,主要是分为两大类:数据转发到指定端口.数据扩散到所有端口. 下面就从这两方面进行分析: 一  数据转发到指定端口 对于数据转发到指定端口的功能,也可以分为两个方面:对入口流量进行的 ...

  5. Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

    Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...

  6. lighttpd1.4.18代码分析

    lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1)  编辑 lig ...

  7. 内核RDMA模块(siw)代码分析

    siw是内核中实现的RDMA设备驱动模块.与其他RDMA设备驱动不同的是,这个模块没有对应的硬件设备,而是通过软件方式模拟了一个使用iWARP协议的RDMA设备,通过内核的socket接口完成tcp报 ...

  8. Linux GIC代码分析

    一.前言 GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器,其architecture specification目前有四个版本,V1-V4(V ...

  9. lego-loam代码分析(3)-激光里程计

    lego-loam代码分析(3)-激光里程计 匹配初始化 TransformToStart TransformToEnd 两次LM匹配 平面匹配 匹配点查找 目标点到匹配平面的距离 LM求解 角点匹配 ...

最新文章

  1. 需求分析--12章 过程建模
  2. html打开新窗口设置窗口属性,HTML之:让网页中的a标签属性统一设置-如‘新窗口打开’...
  3. jfinal整合quartz实现定时任务的两种方式
  4. 查询数据库中所有表名称
  5. Project Euler Problem 25 1000-digit Fibonacci number
  6. 水平面天文辐射网络模拟(基于ArcGIS)
  7. 怎么修改PDF文件内容,PDF怎么删除其中一页
  8. 初入职场不得不掌握的6个好习惯
  9. photoSwipe插件使用
  10. SLAM学习资源分享
  11. onvif 模拟摄像头_ONVIF 设备发现(网络摄像头)——实例笔记
  12. 李开复给中国学生第三封信:成功、自信、快乐
  13. 【贵阳市公积金相关问题】
  14. BiliBili系列(二):个人历史数据爬取与分析
  15. # 代码块 while
  16. linux下Configure命令-ZZT
  17. 如何访问web文件夹之外的文件
  18. 计算机打字工作内容,计算机基础知识打字入门
  19. 关于Xilinx下载器驱动安装及常见问题解决方法
  20. https://dl.bintray.com/scalding/generic/waroverlay.gradle不能访问

热门文章

  1. 为什么有机硅消泡剂会如此受欢迎,到底有什么特点
  2. 五大维度看山东测绘地理信息事业精彩十年
  3. 亚伦斯沃特斯_盒装首席执行官亚伦·莱维(Aaron Levie)胜过科技巨头和股票市场
  4. 用Qt写一个迷宫游戏
  5. python not in range_python报“30 is not in range”的错误应该如何解决?
  6. IBRNet:基于IBR的NeRF
  7. tags文件生成及使用
  8. 永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]
  9. 天之痕人物乱谈 且转一帖[盖棺论定谈陈辅]
  10. android音乐播放器开发在线加载歌词,移动开发平台