Eclipse plugin开发中的ClassNotFoundException问题

来源:互联网 发布:一个人做淘宝 心酸 编辑:程序博客网 时间:2024/05/16 12:08

一 .关于classloader的一些悲剧

加载顺序:parent-first 跟child-first

 说起classloader,就不得不提到这么一篇文章了“Taxonomy of class loader problems encountered when using Jakarta Commons Logging“,by Ceki Gülcü,也就是 log4j跟logback的作者。 这是一篇谈common logging在类加载上的问题。 整个示例及文章可以在这里下载到:http://articles.qos.ch/delegation/cl-problems.zip(附件也放了一份),强烈推荐下载了研究一下里面的demo

1.parent-first(

The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When called upon to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the bootstrap class loader, does not itself have a parent but may serve as the parent of a ClassLoader instance.

Thus, parent-first delegation is the default and recommended delegation model in Java.

)

 也就是说,在加载一个类的时候,会通过代理模式去寻找类的parent,并由上而下的顺序进行加载,这种父到子的类加载方式是jdk推荐+默认的。注意,是默认的。

 

2.child-first(

a child class loader may prefer to first attempt to load resources on its own, and only later to delegate to its parent. We refer to this kind of class loaders as following the child-first delegation model. Note that the Servlet Specification only recommends child-first delegation order. In practice, not all Servlet Containers implement the child-first delegation model. Both delegation models are fairly common in practice.)

这里需要注意的是。。Servlet规范只将child-first作为唯一类加载顺序。

二。Elipse插件访问project的NoClassDefFoundError错误

在eclipse插件开发中只有一种次序的parent-first class loader,但是开发过程中同样会碰到NoClassDefFoundError ,那么是什么其他原因呢?

 

目标:“代码生成插件”---选中某个IJavaProject的一个*.java,用ftl模板生成文件,

 

在同一个java项目里面,我们通常使用Class.forName这样的代码来加载class

try {    Class clz = Class.forName("weisong.AbcAction"); //    System.out.println(clz);} catch (ClassNotFoundException e) {    e.printStackTrace();}

,但是这行代码在plugin项目中行不通。。。因为Eclipse自身每个plugin会有自己的类加载器,

并且有自己独特的插件依赖关系定义机制,OS系统的cp变量对其无效!  这里的加载失败不是有序顺序先后导致,而是cp问题,

 

于是在插件代码实现了一个helper类,来解决插件项目访问workspace项目资源的功能: 整个代码最核心的地方就是

将不同loader 的classpath属性进行复制(类定义如果不在cp里面,当然是加载不到的)

/** * 用来加载eclipse workspace里面java项目的class辅助classloader * Class Helper to load class of java project. */public final class ClassHelper {    private static final String PROTOCAL_PREFIX = "file:///";    /**     * get the <code>ClassLoader</code> of java project specified.     *     * @param project <code>IJavaProject</code>     * @return <code>ClassLoader</code> of java project     * @throws CoreException     * @throws MalformedURLException     */    public static ClassLoader getProjectClassLoader(IJavaProject project)            throws CoreException,MalformedURLException {        //compute the project classpaths        //REVIEW: Are the classpaths returned by computeDefaultRuntimeClassPath enough to load class?        String[] classPaths = JavaRuntime.computeDefaultRuntimeClassPath(project);        URL[] urls = new URL[classPaths.length];        for (int i = 0; i < classPaths.length; i++) {                urls[i] = new URL(PROTOCAL_PREFIX + computeForURLClassLoader(classPaths[i]));        }
        return new URLClassLoader(urls);    }    /**     * load <code>Class</code> in java project     *     * @param project <code>IJavaProject</code>     * @param className name of class to load     * @return <code>Class</code>     * @throws ClassNotFoundException     * @throws CoreException     * @throws MalformedURLException     */    public static Class loadClass(IJavaProject project, String className)            throws CoreException, ClassNotFoundException,MalformedURLException {        ClassLoader loader = getProjectClassLoader(project);        Class clazz = loader.loadClass(className);        loader = null;        return clazz;    }    /**     * transform the <code>IType</code> to <code>Class</code>     *     * @param type <code>IType</code>     * @return <code>Class</code>     * @throws ClassNotFoundException     * @throws MalformedURLException     */    public static Class typeToClass(IType type) throws CoreException,            ClassNotFoundException,MalformedURLException {        try {            if (null != type && (type.isClass() || type.isInterface())) {                String className = type.getFullyQualifiedName('$');                return loadClass(type.getJavaProject(), className);            }        } catch (JavaModelException e) {            e.printStackTrace();        }        return null;    }    /**     * because of URLClassLoader assumes any URL not ends with '/' to refer to a     * jar file. so we need to append '/' to classpath if it is a folder but not     * ends with '/'.     *     * @param classpath     * @return     */    private static String computeForURLClassLoader(String classpath) {        if (!classpath.endsWith("/")) {            File file = new File(classpath);            if (file.exists() && file.isDirectory()) {                classpath = classpath.concat("/");            }        }        return classpath;    }}

 

到这里就明白了。。classloader除了不同的实现,还必须注意其classpath属性:)

 

 

另外,plugin项目如果要访问本项目自身的资源,可以这么来

//plugin项目本身路径:String location = Platform.getBundle("API_GEN").getLocation();//"reference:file:/E:/ws1/API_GEN/"//去掉""reference:file:/"location = (String) location.subSequence(16, location.length());  // "E:/ws1/API_GEN/"

 

 

  • cl-problems_精辟.zip (1.1 MB)
  • 下载次数: 57
  • 大小: 46.7 KB
  • 查看图片附件
0 0
原创粉丝点击