Eclipse下的Java类加载器与Eclipse外的Java类加载器不同

Eclipse下的Java类加载器与Eclipse外的Java类加载器不同,java,eclipse,interface,classloader,Java,Eclipse,Interface,Classloader,我已经编写了一个简单的插件系统,这样我就可以包含来自外部源的扩展。插件管理器从预定的应用程序和用户插件目录加载插件。我使用一个定制的URLClassLoader,这样我就可以对所有插件进行沙箱处理。以下是一般方法: 在一个预定的目录中找到插件的JAR文件 如果插件已经加载,则返回已经创建的插件实例 如果尚未为包含插件的目录创建自定义URLClassLoader的实例,请创建一个实例 通过使用class.forName(pluginName,false,PluginClassLoader)加载类,

我已经编写了一个简单的插件系统,这样我就可以包含来自外部源的扩展。插件管理器从预定的应用程序和用户
插件
目录加载插件。我使用一个定制的
URLClassLoader
,这样我就可以对所有插件进行沙箱处理。以下是一般方法:

  • 在一个预定的目录中找到插件的JAR文件
  • 如果插件已经加载,则返回已经创建的插件实例
  • 如果尚未为包含插件的目录创建自定义
    URLClassLoader
    的实例,请创建一个实例
  • 通过使用
    class.forName(pluginName,false,PluginClassLoader)
    加载类,循环浏览插件JAR文件中的每个类,查找实现
    PluginInterface
    的类,然后测试
    PluginInterface
    是否可从加载的类中指定
  • 如果该类实现了
    PluginInterface
    ,则会创建、初始化并保存该类的新实例以供以后使用
  • 当我在EclipseIDE中运行它时,所有这些都非常有效。但是,当我在IDE之外运行它时,检查插件是否实现了
    PluginInterface
    失败。我相信这是因为在Eclipse下,插件和接口都有一个相关的(父级或子级)
    ClassLoader
    (即
    sun.misc.Launcher)$AppClassLoader@73d16e93在Eclipse之外,
    PluginInterface
    有一个不相关的
    ClassLoader
    (即
    java.net)。URLClassLoader@14ae5a5

    代码如下:

    自定义
    类加载器

    public class PROD_PluginClassLoader extends URLClassLoader {
    
        protected PROD_PluginClassLoader( URL pluginFileUrl ) {
            super( new URL[] { pluginFileUrl } );
        }
    
        protected PROD_PluginClassLoader( String pluginFilePath ) throws MalformedURLException {
            super( new URL[] { new File( pluginFilePath ).toURI().toURL() } );
        }
    
        protected PROD_PluginClassLoader( URL[] pluginFileUrls ) {
            super( pluginFileUrls );
        }
    
    }
    
        private static List< String > loadedPlugins = new ArrayList<>();
        private static List< PROD_PluginInterface > plugins = new ArrayList<>();
        private static Map< String, PROD_PluginClassLoader > pluginClassLoaders = new HashMap<>();
    
        protected static void getPluginInstance( String pluginName, String pluginFilePath ) {
            try {
                PROD_Utilities.printDebug( "Loading plugin name(" + pluginName + ") from(" + pluginFilePath + ")" );
                if ( !pluginClassLoaders.containsKey( pluginFilePath ) ) pluginClassLoaders.put( pluginFilePath, new PROD_PluginClassLoader( pluginFilePath ) );
                PROD_PluginClassLoader pLoader = pluginClassLoaders.get( pluginFilePath );
                boolean pluginLoaded = false;
                for ( String n : PROD_Utilities.getClassNamesFromJarFile( pluginFilePath ) ) {
                    Class<?> pClass = Class.forName( n, false, pLoader );
                    String interfaces = "";
                    for ( Class<?> c : pClass.getInterfaces() ) interfaces += "," + c.getName();
                    if ( !interfaces.isEmpty() ) interfaces = interfaces.substring( 1 );
                    PROD_Utilities.printDebug( String.format( "Plugin name(%s) object class(%s) super(%s) interfaces(%s) isPlugin(%b)", pluginName, pClass.getName(), pClass.getSuperclass().getName(), interfaces, PROD_PluginInterface.class.isAssignableFrom( pClass ) ) );
    if ( pClass.getInterfaces().length > 0 )
    PROD_Utilities.printDebug(
    String.format(
         "pClass loader(%s) parent(%s) pClass interface loader(%s) parent(%s) PROD_PluginInterface loader(%s) parent(%s)"
        ,pClass.getClassLoader()
        ,pClass.getClassLoader().getParent()
        ,pClass.getInterfaces()[0].getClassLoader()
        ,pClass.getInterfaces()[0].getClassLoader().getParent()
        ,PROD_PluginInterface.class.getClassLoader()
        ,PROD_PluginInterface.class.getClassLoader().getParent()
    ));
                    if ( PROD_PluginInterface.class.isAssignableFrom( pClass ) ) {
                        Class<? extends PROD_Plugin> newClass = pClass.asSubclass( PROD_Plugin.class );
                        Constructor<?> constructor = newClass.getConstructor();
                        setPluginSandbox();
                        plugins.add( ( PROD_PluginInterface ) constructor.newInstance() );
                        plugins.get( plugins.size()-1 ).pluginInitialization();
                        unsetPluginSandbox();
                        pluginLoaded = true;
                    }
                }
                if ( pluginLoaded ) loadedPlugins.add( pluginName.toLowerCase() );
                else PROD_Utilities.printError( "Plugin (" + pluginName + ") is not a valid PROD plugin." );
            } catch ( InstantiationException    | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException | ClassNotFoundException | NoSuchMethodException 
                    | SecurityException         | MalformedURLException     e ) {
                PROD_Utilities.printError( "Could not load plugin (" + pluginName + ").", e.getMesprod() );
            }
        }
    
    插件加载程序

    public class PROD_PluginClassLoader extends URLClassLoader {
    
        protected PROD_PluginClassLoader( URL pluginFileUrl ) {
            super( new URL[] { pluginFileUrl } );
        }
    
        protected PROD_PluginClassLoader( String pluginFilePath ) throws MalformedURLException {
            super( new URL[] { new File( pluginFilePath ).toURI().toURL() } );
        }
    
        protected PROD_PluginClassLoader( URL[] pluginFileUrls ) {
            super( pluginFileUrls );
        }
    
    }
    
        private static List< String > loadedPlugins = new ArrayList<>();
        private static List< PROD_PluginInterface > plugins = new ArrayList<>();
        private static Map< String, PROD_PluginClassLoader > pluginClassLoaders = new HashMap<>();
    
        protected static void getPluginInstance( String pluginName, String pluginFilePath ) {
            try {
                PROD_Utilities.printDebug( "Loading plugin name(" + pluginName + ") from(" + pluginFilePath + ")" );
                if ( !pluginClassLoaders.containsKey( pluginFilePath ) ) pluginClassLoaders.put( pluginFilePath, new PROD_PluginClassLoader( pluginFilePath ) );
                PROD_PluginClassLoader pLoader = pluginClassLoaders.get( pluginFilePath );
                boolean pluginLoaded = false;
                for ( String n : PROD_Utilities.getClassNamesFromJarFile( pluginFilePath ) ) {
                    Class<?> pClass = Class.forName( n, false, pLoader );
                    String interfaces = "";
                    for ( Class<?> c : pClass.getInterfaces() ) interfaces += "," + c.getName();
                    if ( !interfaces.isEmpty() ) interfaces = interfaces.substring( 1 );
                    PROD_Utilities.printDebug( String.format( "Plugin name(%s) object class(%s) super(%s) interfaces(%s) isPlugin(%b)", pluginName, pClass.getName(), pClass.getSuperclass().getName(), interfaces, PROD_PluginInterface.class.isAssignableFrom( pClass ) ) );
    if ( pClass.getInterfaces().length > 0 )
    PROD_Utilities.printDebug(
    String.format(
         "pClass loader(%s) parent(%s) pClass interface loader(%s) parent(%s) PROD_PluginInterface loader(%s) parent(%s)"
        ,pClass.getClassLoader()
        ,pClass.getClassLoader().getParent()
        ,pClass.getInterfaces()[0].getClassLoader()
        ,pClass.getInterfaces()[0].getClassLoader().getParent()
        ,PROD_PluginInterface.class.getClassLoader()
        ,PROD_PluginInterface.class.getClassLoader().getParent()
    ));
                    if ( PROD_PluginInterface.class.isAssignableFrom( pClass ) ) {
                        Class<? extends PROD_Plugin> newClass = pClass.asSubclass( PROD_Plugin.class );
                        Constructor<?> constructor = newClass.getConstructor();
                        setPluginSandbox();
                        plugins.add( ( PROD_PluginInterface ) constructor.newInstance() );
                        plugins.get( plugins.size()-1 ).pluginInitialization();
                        unsetPluginSandbox();
                        pluginLoaded = true;
                    }
                }
                if ( pluginLoaded ) loadedPlugins.add( pluginName.toLowerCase() );
                else PROD_Utilities.printError( "Plugin (" + pluginName + ") is not a valid PROD plugin." );
            } catch ( InstantiationException    | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException | ClassNotFoundException | NoSuchMethodException 
                    | SecurityException         | MalformedURLException     e ) {
                PROD_Utilities.printError( "Could not load plugin (" + pluginName + ").", e.getMesprod() );
            }
        }
    
    在Eclipse之外运行时的调试信息:

     Debug: PROD_PluginManager.getPluginInstance().line(138): Loading plugin name(proddb) from(C:\Users\userid\eclipse-workspace\prod\plugins\proddb.jar)
     Debug: PROD_PluginManager.getPluginInstance().line(147): Plugin name(proddb) object class(com.company.prod.proddb.PRODDB) super(com.company.prod.PROD_Plugin) interfaces(com.company.prod.PROD_PluginInterface) isPlugin(false)
     Debug: PROD_PluginManager.getPluginInstance().line(149): pClass loader(com.company.prod.PROD_PluginClassLoader@12405818) parent(sun.misc.Launcher$AppClassLoader@55f96302) pClass interface loader(sun.misc.Launcher$AppClassLoader@55f96302) parent(sun.misc.Launcher$ExtClassLoader@3d3fcdb0) PROD_PluginInterface loader(java.net.URLClassLoader@14ae5a5) parent(null)
    
    我觉得很奇怪,
    PluginInterface
    ClassLoader
    变成了
    urlclasloader

    我认为问题在于
    PluginInterface
    和插件没有共享相关的
    ClassLoader
    ,因此插件的
    PluginInterface
    在技术上与应用程序的
    PluginInterface
    不同。如果该评估是正确的,那么我的问题是如何解决这个问题,以便
    PluginInterface
    和插件共享相关的
    ClassLoader

    或者,也许我的评估是错误的。在这种情况下,我的问题是为什么插件似乎没有实现
    PluginInterface

    我已经为此绞尽脑汁好几天了,所以提前感谢您提供的所有答案

    编辑 我的代码(不是插件)是如何加载的

    从Eclipse内部:使用Eclipse
    Run->Run
    菜单选项


    在Eclipse之外:
    java-jar prod.jar

    很长一段时间后,我终于明白了这一点,并将我的发现发布在这里,以防其他人在
    isAssignableFrom中遇到类似问题

    当使用Java->Runable JAR文件导出向导从Eclipse导出程序时,我选择了库处理选项将所需库打包到生成的JAR中,并获得了原始帖子中描述的
    isAssignableFrom
    失败。使用库处理选项重新导出后,将所需库提取到生成的JAR中,一切正常。

    等待。。。您的代码(不是插件代码)是如何加载的?我的代码要么通过1)通过Eclipse运行,要么通过2)命令提示符下的java-jar mycide.jar加载。