第一步加载类路径: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)
这里边有一个方法需要注意:
这个方法我们将在第二部分解析。
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; } }