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

class APIRouter(base_wsgi.Router):@classmethoddef factory(cls, global_config, **local_config):return cls(**local_config)

APIRouter的factory方法是一个classmethod,直接调用APIRouter的构造函数,对APIRouter进行初始化。下面重点分析一下APIRouter类的构造函数:

class APIRouter(base_wsgi.Router):def __init__(self, **local_config):mapper = routes_mapper.Mapper()     # 获取routes.Mapper的实例。manager.init()                      # 初始化NeutronManager来读取配置文件和加载plugin,该部分最关键的步骤。plugin = directory.get_plugin()     # 从_PLUGIN_DIRECTORY._plugin中获取core plugin。ext_mgr = extensions.PluginAwareExtensionManager.get_instance()     # 根据所有的plugins获取相应path并加载extensions。ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,member_actions=MEMBER_ACTIONS)def _map_resource(collection, resource, params, parent=None):......mapper.connect('index', '/', controller=Index(RESOURCES))       # http://controller:9696/v2.0/for resource in RESOURCES:_map_resource(RESOURCES[resource], resource,attributes.RESOURCE_ATTRIBUTE_MAP.get(RESOURCES[resource], dict()))resource_registry.register_resource_by_name(resource)for resource in SUB_RESOURCES:_map_resource(SUB_RESOURCES[resource]['collection_name'], resource,attributes.RESOURCE_ATTRIBUTE_MAP.get(SUB_RESOURCES[resource]['collection_name'],dict()),SUB_RESOURCES[resource]['parent'])# Certain policy checks require that the extensions are loaded# and the RESOURCE_ATTRIBUTE_MAP populated before they can be# properly initialized. This can only be claimed with certainty# once this point in the code has been reached. In the event# that the policies have been initialized before this point,# calling reset will cause the next policy check to# re-initialize with all of the required data in place.
        policy.reset()super(APIRouter, self).__init__(mapper)

APIRouter的内容比较复杂,主要分为以下三个部分:
  1. 初始化NeutronManager来加载core plugin和service plugin;
  2. 初始化PluginAwareExtensionManager;
  3. 调用_map_resource方法为四个顶级resource进行map。
下面分为三篇来逐个分析这三个部分。首先是NeutronManager,该部分在APIRouter的构造函数中只有一行代码:
manager.init()

调用/neutron/manager.py中的init方法:

def init():"""Call to load the plugins (core+services) machinery."""# TODO(armax): use is_loaded() when availableif not directory.get_plugins():NeutronManager.get_instance()

首先,调用了neutron_lib库中的plugins.directory.py中的get_plugins方法。这里把相关的方法都贴出来,一起分析。

_PLUGIN_DIRECTORY = None@_synchronized("plugin-directory")
def _create_plugin_directory():global _PLUGIN_DIRECTORYif _PLUGIN_DIRECTORY is None:_PLUGIN_DIRECTORY = _PluginDirectory()return _PLUGIN_DIRECTORYdef _get_plugin_directory():if _PLUGIN_DIRECTORY is None:return _create_plugin_directory()return _PLUGIN_DIRECTORYdef add_plugin(alias, plugin):_get_plugin_directory().add_plugin(alias, plugin)def get_plugin(alias=constants.CORE):return _get_plugin_directory().get_plugin(alias)def get_plugins():return _get_plugin_directory().pluginsdef get_unique_plugins():return _get_plugin_directory().unique_pluginsdef is_loaded():return _get_plugin_directory().is_loaded

这里申请了一个全局变量_PLUGIN_DIRECTORY,通过_get_plugin_directory方法来获取这个变量,并且在第一次调用_get_plugin_directory方法(即_PLUGIN_DIRECTORY为None时)时,对_PLUGIN_DIRECTORY变量进行赋值。这里申明global是为了在函数体内对一个函数体外的变量进行赋值。可以看到_PLUGIN_DIRECTORY变量是_PluginDirectory类的实例,其构造函数稍后分析。
其余几个函数,均首先获取了_PLUGIN_DIRECTORY变量,再对其进行操作。具体含义如下:
add_plugin(alias, plugin):
向_PLUGIN_DIRECTORY添加名为alias的plugin。
get_plugin(alias=constants.CORE):
从_PLUGIN_DIRECTORY中获取名为alias(默认为core plugin)的plugin。
get_plugins():
获取_PLUGIN_DIRECTORY中所有的plugin。
get_unique_plugins():
获取_PLUGIN_DIRECTORY中不同类型的plugin。
is_loaded():
获取_PLUGIN_DIRECTORY是否为None。
_PLUGIN_DIRECTORY变量是_PluginDirectory类的实例,_PluginDirectory类中均有函数或属性与上述几个函数相对应。
class _PluginDirectory(object):"""A directory of activated plugins in a Neutron Deployment.The directory is bootstrapped by a Neutron Manager running inthe context of a Neutron Server process."""def __init__(self):self._plugins = {}                         # 构造函数只是对_plugins属性进行了初始化。def add_plugin(self, alias, plugin):"""Add a plugin of type 'alias'."""self._plugins[alias] = plugindef get_plugin(self, alias):"""Get a plugin for a given alias or None if not present."""p = self._plugins.get(alias)return weakref.proxy(p) if p else None     # 如果没有名为alias的plugin,返回None。否则返回对应plugin的弱引用。
@propertydef plugins(self):                             # _PluginDirectory的plugins属性是一个函数,返回各个plugin的弱引用。"""The mapping alias -> weak reference to the plugin."""return dict((x, weakref.proxy(y))for x, y in self._plugins.items())@propertydef unique_plugins(self):"""A sequence of the unique plugins activated in the environments."""return tuple(weakref.proxy(x) for x in set(self._plugins.values()))@propertydef is_loaded(self):"""True if the directory is non empty."""return len(self._plugins) > 0

回到/neutron/manager.py中的init方法:

def init():"""Call to load the plugins (core+services) machinery."""# TODO(armax): use is_loaded() when availableif not directory.get_plugins():NeutronManager.get_instance()

第一次调用get_plugins方法,此时_PluginDirectory._plugin为空,返回None。接着,调用NeutronManager的get_instance方法来实际加载各个plugin。
有没有觉得get_instance这个函数名特别眼熟,这里NeutronManager也是一个单例模式的实现。
@six.add_metaclass(profiler.TracedMeta)
class NeutronManager(object):"""Neutron's Manager class.Neutron's Manager class is responsible for parsing a config file andinstantiating the correct plugin that concretely implementsneutron_plugin_base class."""@classmethod@utils.synchronized("manager")def _create_instance(cls):if not cls.has_instance():cls._instance = cls()@classmethoddef has_instance(cls):return cls._instance is not None@classmethoddef get_instance(cls):# double checked lockingif not cls.has_instance():cls._create_instance()return cls._instance

通过对NeutronManager的has_instance的两次判断,确定NeutronManager没有被实例化,这时调用其构造函数:

@six.add_metaclass(profiler.TracedMeta)
class NeutronManager(object):_instance = Nonedef __init__(self, options=None, config_file=None):# If no options have been provided, create an empty dictif not options:options = {}""" 检查配置文件中是否配置了core_plugin,否则抛出异常 """msg = validate_pre_plugin_load()if msg:LOG.critical(msg)raise Exception(msg)# NOTE(jkoelker) Testing for the subclass with the __subclasshook__#                breaks tach monitoring. It has been removed#                intentionally to allow v2 plugins to be monitored#                for performance metrics.plugin_provider = cfg.CONF.core_plugin                      # 从配置文件中获取core_plugin,一般为ml2LOG.info(_LI("Loading core plugin: %s"), plugin_provider)   # server.log中打印 INFO neutron.manager [-] Loading core plugin: ml2# NOTE(armax): keep hold of the actual plugin objectplugin = self._get_plugin_instance(CORE_PLUGINS_NAMESPACE,  # 通过namespace和plugin_provider获取plugin。
                                           plugin_provider)directory.add_plugin(lib_const.CORE, plugin)                # 添加core_plugin(Ml2Plugin的实例)到_PLUGIN_DIRECTORY._plugins中。""" 检查配置文件中的dhcp_agents_per_network,否则抛出异常 """msg = validate_post_plugin_load()if msg:LOG.critical(msg)raise Exception(msg)# load services from the core plugin first
        self._load_services_from_core_plugin(plugin)self._load_service_plugins()                                # 加载service_plugins,包括配置文件中指定的和默认的。# Used by pecan WSGIself.resource_plugin_mappings = {}self.resource_controller_mappings = {}self.path_prefix_resource_mappings = defaultdict(list)

在构造函数中,分别对core plugin和service plugin进行了初始化,并调用directory.add_plugin将各个plugin的实例添加到_PLUGIN_DIRECTORY变量中,供之后调用。其中,core plugin是直接调用_get_plugin_instance方法来获取相应的plugin类(一般为Ml2Plugin)并初始化:

class NeutronManager(object):def _get_plugin_instance(self, namespace, plugin_provider):                 # 通过不同的namespace中的plugin_provider获取相应的plugin。plugin_class = self.load_class_for_provider(namespace, plugin_provider) # 调用load_class_for_provider函数来返回Plugin类。return plugin_class()                                                   # 实例化Plugin类,在此处完成各个plugin的__init__方法的调用。

而service plugin是直接调用_load_service_plugins方法来加载的,但这个方法也是通过_get_plugin_instance方法来加载各个service plugin。
通过_load_service_plugins方法加载的service plugin分为两种:一种为配置文件中指定的service_plugins,另一种为默认的service plugins,由函数_get_default_service_plugins获取。
总结:
各个plugin的加载均是通过NeutronManager以单例模式的方式在其构造函数中实现的,而各个plugin在初始化后的实例均以{名称:对应plugin类的实例}这样的字典方式保存在变量_PLUGIN_DIRECTORY中,供之后的各个流程调用。

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

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

  1. Ocata Neutron代码分析(六)——APIRouter的初始化(2)PluginAwareExtensionManager的初始化...

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

  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. DSS 代码分析【启动、初始化流程】

    DSS加载module及和module交互的流程,如下: (1).DSS在fork子进程后调用StartServer启动服务 调用OS.OSThread.Socket.SocketUtils.QTSS ...

  5. GMap.NET入门详细教程【2】-------- 初始化并加载一张地图

    GMap.NET入门 下载 GMap.NET,并在VS中添加GMap.NET控件 初始化并加载一张地图 添加标记点.线.多边形 为控件添加事件,在鼠标单击时打点 初始化 双击地图控件,编辑cs代码中的 ...

  6. java 初始化的加载顺序问题

    总结一下java里面关于初始化的加载顺序问题: 考虑有一个基类和一个子类的情况 那么,当实例化一个子类的对象或者访问子类的静态域或静态方法时,会进行类的加载. 1)完成基类的static域和stati ...

  7. SpringMVC--Ajax异步加载数据$(function (){ 逻辑代码}) 的意思是让dom结构加载完毕后再去执行逻辑代码

    1. SpringMVC–Ajax异步加载数据 1.1 实体类user User.java package com.tian.pojo;import lombok.AllArgsConstructor ...

  8. inputstream 初始化_MyBatis初始化之加载初始化

    在MyBatis初始化过程中,大致会有以下几个步骤: 1. 创建Configuration全局配置对象,会往TypeAliasRegistry别名注册中心添加Mybatis需要用到的相关类,并设置默认 ...

  9. Spring Ioc 源码分析(一)--Spring Ioc容器的加载

    1.目标:熟练使用spring,并分析其源码,了解其中的思想.这篇主要介绍spring ioc 容器的加载 2.前提条件:会使用debug 3.源码分析方法:Intellj idea debug 模式 ...

最新文章

  1. 浅说国际根域名服务器与中国电信的镜像服务器
  2. sina stock历史数据
  3. 【设计模式】代理模式 ( 动态代理 | 模拟 Java 虚拟机生成对应的 代理对象 类 )
  4. npp夜光数据介绍 viirs_惊艳!珞珈一号卫星“眼中”的夜光衡水
  5. 学习区块链,绕不过去的“拜占庭将军问题”!!这里正好有通俗易懂的解释
  6. python itchat 的使用
  7. DDG全家桶之3022
  8. C++(STL):35---multimap容器
  9. html + css实现油画商场页面
  10. Bailian2899 Bailian3242 矩阵交换行【矩阵】
  11. 开启NTP时钟服务器,让电脑变成网络时间服务器
  12. C++开发坦克大战--补充(加入传送门)--附完整代码
  13. gps数据处理 java_GPS数据读取与处理
  14. EasyRecovery15绿色版免安装数据恢复软件
  15. 如何选择好的健身房管理系统而且还不收费
  16. 百度地图API仿链家地图找房 聚合开发 js实现
  17. Vue 组件封装之 Result 结果页
  18. scala中sorted,sortby,sortwith的用法(转)
  19. VGA、DVI、HDMI、DP 接口介绍及优劣
  20. Feature Selection详解(附带Relief、Relief-F、LVM详解)(一)

热门文章

  1. 安卓开发中的一些经验总结
  2. B450M MORTAR    AMD R5 3600   组装机
  3. 前后端交互之——AJAX提交
  4. 外贸公司用邮件开发客户需要注意些什么?
  5. Errors while compiling. Reload prevented.
  6. “No JSON object could be decoded“问题定位
  7. codeforces 赛后总结
  8. 分享5款堪称神器的免费软件,建议先收藏再下载
  9. Flink OLAP 助力 ByteHTAP 亮相数据库顶会 VLDB
  10. 如何搭建一个属于自己的博客网站?(小白教程)