第一步加载类路径:azkaban.executor.AlerterHolder
allAlerters 是一个HashMap ,key为String
,value为Alerter
mailAlerter是系统内置的,无需处理,这里要加载的是自定义的插件告警
这里边读取配置信息里的alerter.plugin.dir
作为pluginDir,也就是插件文件夹
然后调用了方法loadPluginAlerters(pluginDir)
private Map<String, Alerter> loadAlerters(final Props props, final Emailer mailAlerter) {
final Map<String, Alerter> allAlerters = new HashMap<>();
// load built-in alerters
allAlerters.put("email", mailAlerter);
// load all plugin alerters
final String pluginDir = props.getString("alerter.plugin.dir", "plugins/alerter");
allAlerters.putAll(loadPluginAlerters(pluginDir));
return allAlerters;
}
第二步我们追踪loadPluginAlerters(pluginDir)
这里边有一个方法需要注意:
- Class<?> alerterClass =
PluginUtils.getPluginClass(pluginClass, pluginDir, extLibClassPaths, parentLoader);
这个方法我们将在第二部分解析。
private Map<String, Alerter> loadPluginAlerters(final String pluginPath) {
final File alerterPluginPath = new File(pluginPath);
//如果文件不存在 直接返回一个空集合
if (!alerterPluginPath.exists()) {
return Collections.<String, Alerter>emptyMap();
}
final Map<String, Alerter> installedAlerterPlugins = new HashMap<>();
//获取父类加载器
final ClassLoader parentLoader = getClass().getClassLoader();
//获取插件目录下的所有文件
final File[] pluginDirs = alerterPluginPath.listFiles();
final ArrayList<String> jarPaths = new ArrayList<>();
//遍历所有插件目录下的所有文件
for (final File pluginDir : pluginDirs) {
// load plugin properties
// 读取配置文件pluginDir下的自定义alert文件夹中的con目录下的plugin.properties
final Props pluginProps = PropsUtils.loadPluginProps(pluginDir);
if (pluginProps == null) {
continue;
}
//如果获取到配置文件,则读取如下三个配置信息
final String pluginName = pluginProps.getString("alerter.name");
final List<String> extLibClassPaths =
pluginProps.getStringList("alerter.external.classpaths",
(List<String>) null);
final String pluginClass = pluginProps.getString("alerter.class");
//alerter.class是必须要配置的
if (pluginClass == null) {
logger.error("Alerter class is not set.");
continue;
} else {
logger.info("Plugin class " + pluginClass);
}
//加载所有的plugin类
Class<?> alerterClass =
PluginUtils.getPluginClass(pluginClass, pluginDir, extLibClassPaths, parentLoader);
if (alerterClass == null) {
continue;
}
//获取类的.class路径
final String source = FileIOUtils.getSourcePathFromClass(alerterClass);
logger.info("Source jar " + source);
jarPaths.add("jar:file:" + source);
Constructor<?> constructor = null;
try {
constructor = alerterClass.getConstructor(Props.class);
} catch (final NoSuchMethodException e) {
logger.error("Constructor not found in " + pluginClass);
continue;
}
//反射方法获取插件对象
Object obj = null;
try {
obj = constructor.newInstance(pluginProps);
} catch (final Exception e) {
logger.error(e);
}
if (!(obj instanceof Alerter)) {
logger.error("The object is not an Alerter");
continue;
}
final Alerter plugin = (Alerter) obj;
installedAlerterPlugins.put(pluginName, plugin);
}
//将所有插件类型以及所属对象放入Map中返回
return installedAlerterPlugins;
}
/**
* Get URLClassLoader
*/
public static URLClassLoader getURLClassLoader(final File pluginDir,
List<String> extLibClassPaths,
ClassLoader parentLoader) {
final File libDir = new File(pluginDir, LIBRARY_FOLDER_NAME);
if (libDir.exists() && libDir.isDirectory()) {
final File[] files = libDir.listFiles();
final ArrayList<URL> urls = getUrls(files);
if (extLibClassPaths != null) {
for (final String extLibClassPath : extLibClassPaths) {
try {
final File extLibFile = new File(pluginDir, extLibClassPath);
if (extLibFile.exists()) {
if (extLibFile.isDirectory()) {
// extLibFile is a directory; load all the files in the
// directory.
final File[] extLibFiles = extLibFile.listFiles();
urls.addAll(getUrls(extLibFiles));
} else {
final URL url = extLibFile.toURI().toURL();
urls.add(url);
}
} else {
logger.error(
"External library path not found. path = " + extLibFile.getAbsolutePath()
);
continue;
}
} catch (final MalformedURLException e) {
logger.error(
"Invalid External library path. path = " + extLibClassPath + " dir = " + pluginDir,
e
);
}
}
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentLoader);
} else {
logger.error("Library path not found. path = " + libDir);
return null;
}
}