Floodlight源码分析(1)
基本概念
在详细分析模块加载过程之前,先了解几个核心概念。
1.模块(Module)
Module是指继承了IFloodlightModule接口的类。IFloodlightModule定义如下:
|
|
我们知道,在Java中,一个类,可以有多个实例。但在Floodlight系统中,每个Module类只包含一个module实例。Module类通过ServiceLoader只实例化一个module实例,类似于Spring框架的功能,详见3.2.2节。
(约定:以下内容中,首字母大写的Module表示类,小写的module表示实例)
2.服务(Service)
Service是指继承了IFloodlightService接口的类。IFloodlightService定义如下,是一个空接口,保证类型安全:
|
|
3.配置需要启动的Module
Floodlight从命令行启动的时候,可以加上配置文件参数(见第2节);如果没有添加,则启动默认的配置文件。
可以在这个配置文件中定义一个Module列表,这些Module在Floodlight运行的时候自动启动。
4.Module与Service的关系
- 一个Module可以包含多个Service。
- 一个Service也可以被多个Module包含。
- 但是,对于定义在配置文件(见3.2.1)中将要启动的Module,任意两个Module不能包含相同的Service。
总结一下:Module和Service可以是Many-to-Many的关系;但是对于定义在配置文件中的所有Module,是one-to-Many的关系。
5.依赖关系
一个Module可能依赖于多个Service,通过调用getModuleDependencies方法获取module实例所依赖的Service。
定义在配置文件的Module在启动前,程序会解决依赖问题。如果一个Module依赖一个Service,那么程序会加载包含这个Service的Module解决依赖。如果包含这个Service的Module有多个,那么必须选一个,显式写在配置文件中。
Main函数
main函数很简单(除去注释、空行,只有十几行),也很容易理解,主要包括以下几部分内容:
- 解析命令行参数
- 加载自定义模块
- 启动REST服务器
- 启动Controller
这几部分在接下来的几节中详细论述。
命令行参数解析
程序使用CmdLineParser解析命令参数。CmdLineSetting定义了命令行参数的格式:-cf[--configFile] FILE
,用来通过命令行传入配置文件路径。
|
|
默认情况下,配置文件路径为“config/floodlight.properties”。
FloodlightModuleLoader
从主函数可以看到,它实例化了FloodlightModuleLoader,用来加载模块,而这个类也继承了IFloodlightService接口,所以它可以看作是一种特殊的Service,用来加载Module的Service。
在详细说明FloodlightModuleLoader功能之前,我先介绍一下它内部的几个静态成员变量:
- serviceMap:Service类型与所属的多个modules实例的映射关系
- moduleService:module实例与包含的Services类型的映射关系
- moduleNameMap:Module名称与module实例的映射关系
FloodlightModuleLoader主要做了三件事(loadModulesFromConfig方法):
- 解析配置文件,读取其中的Module名称(用于第三步启动)
- 利用ServiceLoader实例化所有Module
- 对于2中的所有实例,只启动配置文件所定义的类型
1.解析配置文件
参见loadModulesFromConfig方法。
配置文件是Properties文件,以等号(“=”)分隔属性名和属性值,使用java.util.Properties
就可以解析。
- “floodlight.modules”属性对应的值是以逗号分隔的Module类名字符串。这表示要启动的多个模块。
- “floodlight.confd”属性对应的值是子配置文件目录。这个目录可以包含多个子配置文件,每个文件中也可以包含“floodlight.modules”属性,对应的以逗号分隔Module名也需要被启动。
第1步:将“floodlight.modules”属性定义的多个Module类名,存放到列表中
第2步:如果有“floodlight.confd”属性,解析对应的子配置文件目录,递归解析所有的子配置文件
第3步:返回结果列表
2.实例化所有Module
这部分的内容主要包含在findAllModules方法中。
ServiceLoader是Java SE 6所提供的API,用于自动实例化继承了给定接口(或抽象类)的类,类似于Spring依赖注入的功能。
ServiceLoader的使用请参见《ServiceLoader的使用》
ServiceLoader为resource/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
文件中定义的所有类都创建了一个实例。这些类全部实现了IFloodlightModule,所以可以这么说,ServiceLoader为这个文件中所有的Module创建了一个实例。
然后更新serviceMap、moduleService和moduleNameMap这三个静态变量。
最后,检查配置文件中包含的Module类,是否存在两个以上的Module包含相同的service,否则抛出异常。
3.启动配置文件定义的Module
这部分内容主要在loadModulesFromList方法中。主要过程为:
- 将需启动的Module实例加入到启动列表中
- 将依赖的Module实例加入启动列表中(递归添加依赖Module)
- 启动上述列表中的所有实例
从“解析配置文件”小节中已知道,解析配置文件后,返回一个列表(Collection<String>
),其中包含要启动的Module名称。接下来,循环迭代这个列表,根据Module名称从moduleNameMap中获取对应的module实例。然后把这个实例添加到启动列表中。
如果这个module实例依赖于其他一个或多个Service,那么需要解决依赖,将包含这些Service的module实例也添加到启动列表。