了解urlclassloader,如何访问已加载的jar类

时间:2014-01-12 11:17:33

标签: java jgroups urlclassloader

我试图了解如何使用URLClassLoader访问/提供jar文件。

首先我用

加载jar文件
    package myA;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import org.jgroups.JChannel;



public class loader {

    JChannel channel;

        String user_name=System.getProperty("user.name", "n/a");


        private void start() throws Exception {

            channel=new JChannel(); // use the default config, udp.xml

            channel.connect("ChatCluster");

        }

    public void loadMe()throws ClassNotFoundException, MalformedURLException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        URL classUrl;
        classUrl = new URL("file:///home/myJars/jgroups-3.4.2.Final.jar");
        URL[] classUrls = { classUrl };
        URLClassLoader ucl = new URLClassLoader(classUrls);
        Class<?> c = ucl.loadClass("org.jgroups.JChannel");
        for(Field f: c.getDeclaredFields()) {
            System.out.println("Field name=" + f.getName());
            }
        Object instance = c.newInstance();  
        //Method theMethod = c.getMethod("main");
        //theMethod.invoke(instance);
        }

     public static void main(String[] args) throws Exception {
         new loader().loadMe();
         new  loader().start();

     }
}

打印输出显示jgroups-3.4.2.Final.jar中的声明字段,但是它会抛出classnotfound错误。

java -cp myA.jar myA.loader
Field name=DEFAULT_PROTOCOL_STACK
Field name=local_addr
Field name=address_generator
Field name=name
Field name=cluster_name
Field name=my_view
Field name=prot_stack
Field name=state_promise
Field name=state_transfer_supported
Field name=flush_supported
Field name=config
Field name=stats
Field name=sent_msgs
Field name=received_msgs
Field name=sent_bytes
Field name=received_bytes
Field name=probe_handler
Exception in thread "main" java.lang.NoClassDefFoundError: org/jgroups/JChannel
        at myA.loader.start(loader.java:23)
        at myA.loader.main(loader.java:45)
Caused by: java.lang.ClassNotFoundException: org.jgroups.JChannel
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        ... 2 more

我不明白为什么打印输出显示该类已加载但是找不到它?

THX 领域

2 个答案:

答案 0 :(得分:1)

您的代码可能有几个问题。首先,在main中实例化加载器2次,因此第二个实例独立于第一个实例,可能不知道第一个实例加载了JChannel的类文件定义。

此外,您之前已将JChannel定义为loader的成员,因此JRE在启动时应该要求它的类定义 - 否则它不应该知道该字段应该是什么。我已将您通过URLClassLoader加载的类替换为start(),您应该在package myA; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import org.jgroups.JChannel; public class Loader { Class<?> clazz; String user_name=System.getProperty("user.name", "n/a"); private void start() throws Exception { if (this.clazz == null) throw new Exception("Channel class was not loaded properly"); Object channel = this.clazz.newInstance(); // use the default config, udp.xml Method chatCluster = this.clazz.getDeclaredMethod("connect", new Class[] { String.class }); chatCluster.invoke(channel, "ChatCluster"); } public void loadMe() throws Exception { URL classUrl; classUrl = new URL("file:///home/myJars/jgroups-3.4.2.Final.jar"); URL[] classUrls = { classUrl }; URLClassLoader ucl = new URLClassLoader(classUrls); Class<?> c = ucl.loadClass("org.jgroups.JChannel"); for(Field f: c.getDeclaredFields()) { System.out.println("Field name=" + f.getName()); } this.clazz = c; Object instance = c.newInstance(); //Method theMethod = c.getMethod("main"); //theMethod.invoke(instance); } public static void main(String[] args) throws Exception { Loader loader = new Loader(); loader.loadMe(); loader.start(); } } 中进行实例化。

{{1}}

您应该进一步为代码添加一些错误处理。

答案 1 :(得分:0)

Exception in thread "main" java.lang.NoClassDefFoundError: org/jgroups/JChannel
    at myA.loader.start(loader.java:23)

代码在此行上失败:

       channel=new JChannel(); // use the default config, udp.xml

加载程序 ClassLoader 不会显示 JChannel 类型。如果您尝试这将是显而易见的:

       loader.class
             .getClassLoader()
             .loadClass("org.jgroups.JChannel");

您不应该对在运行时不在类型的类路径上的依赖项进行任何编译时引用。

使用新子 ClassLoader 加载不会将该类型添加到某个全局类池。加载器具有层次结构,具有子父关系。