1

3 つの Jar ファイルがあります。すべての jar ファイルには、同じクラス TestServicesImpl と同じメソッド displayWeLcomeMessage() が含まれていますが、displayWeLcomeMessage() の異なるメッセージ (出力) があります。 例 :

public void displayWeLcomeMessage() {
        System.out.println("wecome msg of JAR version first");

    }

 public void displayWeLcomeMessage() {
            System.out.println("wecome msg of JAR version two");

        }

 public void displayWeLcomeMessage() {
            System.out.println("wecome msg of JAR version third");

        }

私は1つのメインアプリケーションを持っており、それにはjarが含まれています。私のメイン アプリケーションは、displayWeLcomeMessage() メソッドを呼び出します。

最初の JAR がクラスパスに追加され、2 番目の JAR がカスタム クラスローダーでロードされ、メソッド displayWeLcomeMessage() が呼び出されます。

    File file  = new File("C:/Users/amitk/Desktop/Test_1.0.2.jar");
    @SuppressWarnings("deprecation")
    URL url = file.toURL();  
    URL[] urls = new URL[]{url};
    URLClassLoader  loader = new URLClassLoader(urls);

    Class classS = loader.loadClass("com.amit.servicesImpl.TestServicesImpl");
    Object object = classS.newInstance();
    Method getmsg = classS.getMethod("displayWeLcomeMessage");
     getmsg.invoke(object);

ただし、最初に JAR のメソッドと同じメッセージが表示されます。3 番目の JAR で、パッケージ名を変更しました。つまり、 com.amit.servicesImpl.TestServicesImplがcom.amit.servicesImpl2.TestServicesImplに変更され 、今回は正常に動作し、JAR 3 のメソッドのメッセージがここに表示されます。

この背後にある主な問題とその解決策を教えてください。

4

2 に答える 2

2

おそらく、最初のクラスローダーに JAR があるでしょう。URLClassLoader は、自身のスペースをチェックインする前に、親クラス ローダーの既存のクラスをチェックします。

1) この動作を拡張および変更できます。

package com.mytool;

import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;

public class MyURLClassLoader extends URLClassLoader {

    private final Map<String, Class<?>> ourClasses = new HashMap<>();

    public MyURLClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public MyURLClassLoader(URL[] urls) {
        super(urls);
    }

    public MyURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = ourClasses.get(name);

            if (c == null) {
                // search in our paths
                try {
                    c = findClass(name);
                    ourClasses.put(name, c);
                } catch (ClassNotFoundException e) {
                    // ignore
                }
            }

            if (c == null) {
                c = findLoadedClass(name);
            }

            if (c != null) {
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }

            // default search
            return super.loadClass(name, resolve);
        }
    }
}

2) または、JAR を移動して、JVM の開始時にロードしないようにすることもできます。

注: 完全な再帰性を使用する代わりに、最初のクラスローダーによってのみ読み込まれるインターフェイスを使用します。あなたのオブジェクトはそれを実装することができ、このインターフェースにキャストすることができます。MyURLClassLoader を使用してこれを行う場合は、動的に読み込まれる JAR にこのインターフェイスを追加しないでください。

于 2013-10-25T12:42:42.610 に答える