简体   繁体   English

如何从java maven项目中的两个不同版本的jar加载类的两个版本?

[英]How to load two versions of a class from two different versions of jars in a java maven project?

I have a maven project which has a dependency on a jar "sample" of version "2.0". 我有一个Maven项目,该项目依赖于版本“ 2.0”的jar“样本”。 The "sample" jar of version "2.0" contains an Enum by the name "SampleEnum". 版本“ 2.0”的“示例” jar包含一个名为“ SampleEnum”的枚举。 The SampleEnum in "2.0" version looks as below “ 2.0”版本中的SampleEnum如下所示

public enum SampleEnum {
    "HERBIVORES",
    "CARNIVORES",
    "OMNIVORES"
}

I want to load the "SampleEnum" class from "sample" jar of version "1.0" in the above mentioned maven java project. 我想从上述maven java项目中的版本“ 1.0”的“ sample” jar中加载“ SampleEnum”类。 The SampleEnum class in "1.0" version looks something as below. “ 1.0”版本中的SampleEnum类如下所示。

public enum SampleEnum {
    "HERBIVORES",
    "CARNIVORES"
}

I used the below code to load the class: 我使用以下代码加载该类:

public class Test
{
    public static void main(String args[]) {
        try {
            URLClassLoader loader1 = new URLClassLoader(new URL[] {new File("sample-1.0.jar").toURL()}, Thread.currentThread().getContextClassLoader());

            Class<?> c1 = loader1.loadClass("SampleEnum");

            for (Object o : c1.getEnumConstants()) {
                System.out.println(o);
            }
        }
        catch(Exception ex)
        {
            System.err.println(ex.getMessage());
        }
    }
}

The Actual Output of the above program is: 上面程序的实际输出为:

HERBIVORES CARNIVORES OMNIVORES 香草草食肉杂草

As I have loaded the class from "sample-1.0" jar I expected the following output: 当我从“ sample-1.0” jar中加载该类时,我期望以下输出:

HERBIVORES CARNIVORES 香草草食肉

May I know the reason why it is loading the class from the dependent jar instead of the specified jar? 我可以知道为什么从依赖的jar而不是指定的jar中加载类的原因吗?

And is there any way to load the enum class from version 1.0 jar in the maven project? 有什么办法可以从Maven项目的1.0版本的jar中加载枚举类?

The reason it is loading the class from the dependent jar is because the loader1 class loader gets the current Thread's context class loader as its parent class loader and that class loader loads classes from the dependent jar. 它从从属jar加载类的原因是因为loader1类加载器将当前线程的上下文类加载器作为其父类加载器,而该类加载器从从属jar加载类。 The public ClassLoader.loadClass(String) method calls into the protected ClassLoader.loadClass(String, boolean) method and that method is documented to explain that the parent class loader is always searched first. 公共ClassLoader.loadClass(String)方法调用受保护的ClassLoader.loadClass(String, boolean)方法,并且记录了该方法的解释以解释始终总是首先搜索父类加载器。 You can, of course, override this behavior by subclassing URLClassLoader and overriding the loadClass(String, boolean) method. 当然,您可以通过URLClassLoader并重写loadClass(String, boolean)方法来覆盖此行为。

org.sample.SampleEnum from sample-1.0.jar org.sample.SampleEnum从样品-1.0.jar

public enum SampleEnum
{
    HERBIVORES,
    CARNIVORES
}

org.sample.SampleEnum from sample-2.0.jar 来自sample-2.0.jar的org.sample.SampleEnum

public enum SampleEnum
{
    HERBIVORES,
    CARNIVORES,
    OMNIVORES
}

Main.java

package com.example.app;

import org.sample.SampleEnum;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

import static java.util.Arrays.asList;

public class Main
{
    public static void main(String[] args)
    {
        System.out.println("v2.0: " + asList(SampleEnum.values()));
        try {
            URLClassLoader loader1 = new CustomURLClassLoader(
                    new URL[] { new File("../sample-1.0/target/sample-1.0.jar").toURL() });

            Class<?> c1 = loader1.loadClass("org.sample.SampleEnum");

            System.out.println("v1.0: " + asList(c1.getEnumConstants()));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

class CustomURLClassLoader extends URLClassLoader
{
    public CustomURLClassLoader(URL[] urls)
    {
        super(urls);
    }

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();

                // First, look in the current ClassLoader
                long t1 = System.nanoTime();
                try {
                    c = findClass(name);
                } catch (ClassNotFoundException ex) {
                    // ClassNotFoundException thrown if class not found
                }

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();

                // Lastly, look in the parent ClassLoader
                try {
                    if (getParent() != null) {
                        c = super.loadClass(name, resolve);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
}

Output: 输出:

$ java -cp sample-app-2.0.jar:sample-2.0.jar com.example.app.Main
v2.0: [HERBIVORES, CARNIVORES, OMNIVORES]
v1.0: [HERBIVORES, CARNIVORES]

For more information, see https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean) 有关更多信息,请参见https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM