• pf4j 插件加载机制


    主要简单说明下pf4j 的插件加载处理
    参考代码 pf4j/src/main/java/org/pf4j/AbstractPluginManager.java

    加载代码

    • loadPlugins 处理
     
        加载处理
        @Override
        public void loadPlugins() {
            log.debug("Lookup plugins in '{}'", pluginsRoots);
            // check for plugins roots
            if (pluginsRoots.isEmpty()) {
                log.warn("No plugins roots configured");
                return;
            }
            pluginsRoots.forEach(path -> {
                if (Files.notExists(path) || !Files.isDirectory(path)) {
                    log.warn("No '{}' root", path);
                }
            });
     
            // get all plugin paths from repository
            // 查找路径
            List<Path> pluginPaths = pluginRepository.getPluginPaths();
     
            // check for no plugins
            if (pluginPaths.isEmpty()) {
                log.info("No plugins");
                return;
            }
     
            log.debug("Found {} possible plugins: {}", pluginPaths.size(), pluginPaths);
     
            // load plugins from plugin paths
            for (Path pluginPath : pluginPaths) {
                try {
                    // 加载发现到的插件,此方法比较重要
                    loadPluginFromPath(pluginPath);
                } catch (PluginRuntimeException e) {
                    log.error(e.getMessage(), e);
                }
            }
     
            // resolve plugins
            try {
               // 解析插件,主要是关于依赖,解析插件描述信息,然后进行插件状态的通知
                resolvePlugins();
            } catch (PluginRuntimeException e) {
                log.error(e.getMessage(), e);
            }
        }
    • loadPluginFromPath 方法
      此方法比较重要,进行了插件的查找以及插件的classloader创建,形成一个插件的基本存储,方便后续流程使用
      PluginWrapper 是一个比较重要的实体,包含了不少关于插件的元数据信息
     
     protected PluginWrapper loadPluginFromPath(Path pluginPath) {
            // Test for plugin path duplication
            String pluginId = idForPath(pluginPath);
            if (pluginId != null) {
                throw new PluginAlreadyLoadedException(pluginId, pluginPath);
            }
     
            // Retrieve and validate the plugin descriptor
            PluginDescriptorFinder pluginDescriptorFinder = getPluginDescriptorFinder();
            log.debug("Use '{}' to find plugins descriptors", pluginDescriptorFinder);
            log.debug("Finding plugin descriptor for plugin '{}'", pluginPath);
            PluginDescriptor pluginDescriptor = pluginDescriptorFinder.find(pluginPath);
            validatePluginDescriptor(pluginDescriptor);
     
            // Check there are no loaded plugins with the retrieved id
            pluginId = pluginDescriptor.getPluginId();
            if (plugins.containsKey(pluginId)) {
                PluginWrapper loadedPlugin = getPlugin(pluginId);
                throw new PluginRuntimeException("There is an already loaded plugin ({}) "
                        + "with the same id ({}) as the plugin at path '{}'. Simultaneous loading "
                        + "of plugins with the same PluginId is not currently supported.\n"
                        + "As a workaround you may include PluginVersion and PluginProvider "
                        + "in PluginId.",
                    loadedPlugin, pluginId, pluginPath);
            }
     
            log.debug("Found descriptor {}", pluginDescriptor);
            String pluginClassName = pluginDescriptor.getPluginClass();
            log.debug("Class '{}' for plugin '{}'",  pluginClassName, pluginPath);
     
            // load plugin
            log.debug("Loading plugin '{}'", pluginPath);
            // 此处,保证每个插件会有一个不同的classloader,这个后续会介绍
            ClassLoader pluginClassLoader = getPluginLoader().loadPlugin(pluginPath, pluginDescriptor);
            log.debug("Loaded plugin '{}' with class loader '{}'", pluginPath, pluginClassLoader);
     
            PluginWrapper pluginWrapper = createPluginWrapper(pluginDescriptor, pluginPath, pluginClassLoader);
     
            // test for disabled plugin
            if (isPluginDisabled(pluginDescriptor.getPluginId())) {
                log.info("Plugin '{}' is disabled", pluginPath);
                pluginWrapper.setPluginState(PluginState.DISABLED);
            }
     
            // validate the plugin
            if (!isPluginValid(pluginWrapper)) {
                log.warn("Plugin '{}' is invalid and it will be disabled", pluginPath);
                pluginWrapper.setPluginState(PluginState.DISABLED);
            }
     
            log.debug("Created wrapper '{}' for plugin '{}'", pluginWrapper, pluginPath);
     
            pluginId = pluginDescriptor.getPluginId();
     
            // add plugin to the list with plugins
            plugins.put(pluginId, pluginWrapper);
            getUnresolvedPlugins().add(pluginWrapper);
     
            // add plugin class loader to the list with class loaders
            getPluginClassLoaders().put(pluginId, pluginClassLoader);
     
            return pluginWrapper;
        }

    说明

    以上是关于pf4j 插件加载的简单说明,实际上pf4j还包含插件的unload start stop。。。后续会介绍

    参考资料

    https://pf4j.org/doc/plugin-lifecycle.html
    https://pf4j.org/doc/plugins.html

  • 相关阅读:
    C语言网 蓝桥杯 1117K-进制数
    C语言网蓝桥杯1116 IP判断
    LeetCode 面试题14- II. 剪绳子 II
    LeetCode 面试题06. 从尾到头打印链表
    LeetCode 面试题05. 替换空格
    LeetCode 面试题04. 二维数组中的查找
    LeetCode 面试题03. 数组中重复的数字
    LeetCode 3. 无重复字符的最长子串
    LeetCode 202. 快乐数
    LeetCode 154. 寻找旋转排序数组中的最小值 II
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/15902003.html
Copyright © 2020-2023  润新知