2017-01-23 8 views
1

Ich habe ein Maven-Projekt, das eine Abhängigkeit von einem Jar "Probe" der Version "2.0" hat. Die "Probe" Jar der Version "2.0" enthält eine Enum mit dem Namen "SampleEnum". Die SampleEnum in "2.0" Version sieht wie untenWie laden Sie zwei Versionen einer Klasse aus zwei verschiedenen Versionen von Jars in einem Java-Maven-Projekt?

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

ich die "SampleEnum" Klasse von "Probe" Glas-Version "1.0" in dem oben erwähnten Maven Java-Projekt laden möge. Die SampleEnum-Klasse in "1.0" Version sieht etwas wie unten.

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

verwendete ich den folgenden Code, um die Klasse zu laden:

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()); 
     } 
    } 
} 

die tatsächliche Ausgabe des obigen Programms ist:

HERBIVORES CARNIVORES ALLESFRESSER

Wie ich geladen haben die Klasse von "Probe-1.0" Glas Ich erwartete die folgende Ausgabe:

HERBIVORES CARNIVORES

Kann ich kenne den Grund, warum es die Klasse aus dem abhängigen Glas anstelle der angegebenen jar Laden?

Und gibt es eine Möglichkeit, die Enum-Klasse von Version 1.0 jar im Maven-Projekt zu laden?

Antwort

1

Der Grund für das Laden der Klasse aus dem abhängigen Jar ist, dass der Klassenlader loader1 den Kontextklassenlader des aktuellen Threads als übergeordneten Klassenlader erhält und der Klassenlader Klassen aus dem abhängigen Jar lädt. Die öffentliche Methode ClassLoader.loadClass(String) ruft die geschützte Methode ClassLoader.loadClass(String, boolean) auf, und diese Methode wird dokumentiert, um zu erklären, dass der Elternklassenlader immer zuerst durchsucht wird. Sie können dieses Verhalten natürlich überschreiben, indem Sie URLClassLoader untergliedern und die Methode loadClass(String, boolean) überschreiben.

org.sample.SampleEnum von Probe-1.0.jar

public enum SampleEnum 
{ 
    HERBIVORES, 
    CARNIVORES 
} 

org.sample.SampleEnum von Probe-2.0.jar

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] 

Weitere Informationen finden Sie https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String,%20boolean)

+0

den obigen Code verwenden ich die folgende Ausnahme bin immer. Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Object – user3351074

+0

Verursacht durch: java.lang.ClassNotFoundException: java.lang.Object \t bei java.net.URLClassLoader.findClass (URLClassLoader.java:381) \t bei CustomURLClassLoader.loadClass (CustomURLClassLoader.java:22) \t bei java.lang.ClassLoader.loadClass (ClassLoader.Java: 357) – user3351074

+0

Ich sehe diesen Fehler in meinem Code nicht. Ich habe mein Beispiel aktualisiert, um genau zu zeigen, was ich gerade mache. –

Verwandte Themen