• pf4j 类加载顺序简单说明


    pf4j 具有类隔离特性
    参考代码
    pf4j/src/main/java/org/pf4j/ClassLoadingStrategy.java
    pf4j/src/main/java/org/pf4j/PluginClassLoader.java
    pf4j/src/main/java/org/pf4j/DefaultPluginManager.java

    加载顺序

    • 顺序说明(注意顺序)
     
    - 如果类是系统类,使用系统类加载器
    - 如果是pf4j引擎的,使用应用加载器
    - 尝试加载插件的类
    - 插件的没有,委托到依赖的类加载器
    - 然后在委托到父加载器

    参考原理

    • 调用类加载器的方法,在PluginManager 中定义了createPluginLoader,每个PluginLoader 定义了自己的classloader顺序
      我们可以自己编写自己的在扩展
     
    @Override
    protected PluginLoader createPluginLoader() {
        return new CompoundPluginLoader()
            .add(new DevelopmentPluginLoader(this), this::isDevelopment)
            .add(new JarPluginLoader(this), this::isNotDevelopment)
            .add(new DefaultPluginLoader(this), this::isNotDevelopment);
    }
    • pluginloader 参考定义
    public interface PluginLoader {
     
        /**
         * Returns true if this loader is applicable to the given {@link Path}.
         *
         * @param pluginPath
         * @return
         */
        boolean isApplicable(Path pluginPath);
     
        ClassLoader loadPlugin(Path pluginPath, PluginDescriptor pluginDescriptor);
     
    }

    jar 以及DefaultPluginLoader的实现处理都使用了
    pf4j/src/main/java/org/pf4j/PluginClassLoader.java

     
    public PluginClassLoader(PluginManager pluginManager, PluginDescriptor pluginDescriptor, ClassLoader parent) {
        this(pluginManager, pluginDescriptor, parent, ClassLoadingStrategy.PDA);
    }

    顺序如下:
    pf4j/src/main/java/org/pf4j/ClassLoadingStrategy.java

     
    /**
     * plugin -> dependencies -> application(parent)
     */
    public static final ClassLoadingStrategy PDA = new ClassLoadingStrategy(Arrays.asList(Source.PLUGIN, Source.DEPENDENCIES, Source.APPLICATION));
     

    当然系统已经定义了不少其他的可以使用没具体可以参考ClassLoadingStrategy

    • PluginClassLoader 处理
      参考代码
      pf4j/src/main/java/org/pf4j/PluginClassLoader.java
      以下逻辑也印证了官方文档的说法
     
    @Override
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(className)) {
            // first check whether it's a system class, delegate to the system loader
            if (className.startsWith(JAVA_PACKAGE_PREFIX)) {
                return findSystemClass(className);
            }
     
            // if the class is part of the plugin engine use parent class loader
            if (className.startsWith(PLUGIN_PACKAGE_PREFIX) && !className.startsWith("org.pf4j.demo") && !className.startsWith("org.pf4j.test")) {
    //                log.trace("Delegate the loading of PF4J class '{}' to parent", className);
                return getParent().loadClass(className);
            }
     
            log.trace("Received request to load class '{}'", className);
     
            // second check whether it's already been loaded
            Class<?> loadedClass = findLoadedClass(className);
            if (loadedClass != null) {
                log.trace("Found loaded class '{}'", className);
                return loadedClass;
            }
     
            for (ClassLoadingStrategy.Source classLoadingSource : classLoadingStrategy.getSources()) {
                Class<?> c = null;
                try {
                    switch (classLoadingSource) {
                        case APPLICATION:
                            c = super.loadClass(className);
                            break;
                        case PLUGIN:
                            c = findClass(className);
                            break;
                        case DEPENDENCIES:
                            c = loadClassFromDependencies(className);
                            break;
                    }
                } catch (ClassNotFoundException ignored) {}
     
                if (c != null) {
                    log.trace("Found class '{}' in {} classpath", className, classLoadingSource);
                    return c;
                } else {
                    log.trace("Couldn't find class '{}' in {} classpath", className, classLoadingSource);
                }
            }
     
            throw new ClassNotFoundException(className);
        }
    }

    但是有一个问题就是关于自定义PluginClassLoader的问题,官方的文档已经不对了
    我们如果需要对与特定的pluginloader 进行自定义classlaoder ,可以通过重写createPluginLoader以及如下几个方法
    (PluginManager 子类)

     
    protected Map<String, ClassLoader> getPluginClassLoaders() {}
    以及
    public ClassLoader getPluginClassLoader(String pluginId) {}

    当时从目前pf4j 框架来说,改写getPluginClassLoaders 以及getPluginClassLoader 对于系统的机制影响会比较大,推荐还是自己自定义的pluginloader
    加载自己定义的classloader(比如我们我们包装一个基于网络的)

    参考资料

    https://pf4j.org/doc/class-loading.html

  • 相关阅读:
    UNIX网络编程读书笔记:原始套接口
    UNIX网络编程读书笔记:UNIX域协议
    UNIX网络编程读书笔记:名字与地址转换
    链表的游标(cursor)实现
    基数排序
    UNIX网络编程读书笔记:基本SCTP套接口编程
    Android系列之Fragment(三)----Fragment和Activity之间的通信(含接口回调)
    git版本控制工具(二)----本地版本库的常用操作
    Android系列之Fragment(二)----Fragment的生命周期和返回栈
    Git版本控制工具(一)----git的安装及创建版本库
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/15902420.html
Copyright © 2020-2023  润新知