1

数日からこれを試してきましたが、うまくいきません!

コマンドラインから実行し、別のフォルダーにプラグイン (jar) を提供できるプラグイン可能な Java アプリケーションを構築しようとしています。それはServiceLoader私の要件に合っているようですが、jarがクラスパスの一部ではなく、別の場所に保存されているという特別なケースが必要だと思います。このため、ClassLoderこのファイルシステムへのURLを指すを使用する必要があります道。

メイン アプリケーションに提供したいプラグインの 1 つは、いくつかのカスタム機能を備えたログ jar です。

ここで私が使用しているコードの下にありますが、for/loop に入ることができません..これは、ServiceLoaderクラスの実装を識別/一致させることができないことを意味します:

final URL u = new File("C:\\data\\myLogJar-1.0-SNAPSHOT.jar").toURI().toURL();
ClassLoader ucl = new URLClassLoader(new URL[] {u});

ServiceLoader<Log> loader = ServiceLoader.load(Log.class, ucl);
for (Iterator<Log> iterator = loader.iterator(); iterator.hasNext(); ) {
    System.out.println(iterator.next());
}
loader = ServiceLoader.load(Log.class,ucl);
for (final Log log : loader) {
    log.info("Test log");                    
}

お役に立てれば幸いです!どうもありがとう

==== プロジェクト ファイルの追加:

主なプラグイン可能なアプリケーション:

ここに画像の説明を入力

    package com.company.dep.automation;

import com.company.dep.automation.pluggable.Log;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import java.util.*;

public class Main {

    private static ServiceLoader<Log> serviceLoader;

    public static void main(String[] args) {

        final URL u;
        ClassLoader ucl = null;

        try {
            u = new File("C:\\data\\myLogJar-1.0-SNAPSHOT.jar").toURI().toURL();
             ucl = new URLClassLoader(new URL[]{u});
        } catch (MalformedURLException e1) {
            e1.printStackTrace();
        }

        ServiceLoader<Log> loader = ServiceLoader.load(Log.class, ucl);
        for (Iterator<Log> iterator = loader.iterator(); iterator.hasNext(); ) {
            System.out.println(iterator.next());
        }

        loader = ServiceLoader.load(Log.class, ucl);
        for (final Log log : loader) {
            log.info("Test log");
        }

    }

}

「ログ」プラグイン

インターフェイスLog

package com.company.automation.service;

public interface Log {

    void trace(String message);
    void debug(String message);
    void info(String message);
    void warn(String message);
    void severe(String message);
    void error(String message);
    void fatal(String message);

}

その実装

package com.company.automation.service.impl;

import com.company.automation.service.Log;

public class LogImpl implements Log {

    @Override
    public void trace(String message) {
        log("TRACE --> " + message);
    }

    @Override
    public void debug(String message) {
        log("DEBUG --> " + message);
    }

    @Override
    public void info(String message) {
        log("INFO --> " + message);
    }

    @Override
    public void warn(String message) {
        log("WARN --> " + message);
    }

    @Override
    public void severe(String message) {
        log("SEVERE --> " + message);
    }

    @Override
    public void error(String message) {
        log("ERROR --> " + message);
    }

    @Override
    public void fatal(String message) {
        log("FATAL --> " + message);
    }

    private void log(String message) {
        System.out.println(message);
    }

}
  • 構造

ここに画像の説明を入力

=================

プロジェクト構造を次のように調整しましたが、まだ機能しません:

メインアプリ: ここに画像の説明を入力

拡張アプリ: ここに画像の説明を入力

4

2 に答える 2

2

それは同じクラスではないため機能しませんLog。あなたのメインメソッドはの実装を見つけようとしますがcom.company.dep.automation.pluggable.Log、あなたのjarは単に何も見つけることができないcom.company.automation.service.Logような実装を定義しています。ServiceLoader.load

インターフェイスcom.company.automation.service.Logを拡張jarからクラスを使用してプロジェクトに移動し、クラスではなくMainインポートする必要があります。その後、すべてが機能するはずです。com.company.automation.service.Logcom.company.dep.automation.pluggable.LogMain

于 2016-10-27T12:53:04.950 に答える
0

アプリケーションの「プラグ可能な」部分とフォルダーへの jar のロードに関しては、車輪を再発明する代わりに、OSGI を見ることができるかもしれません。OSGI 実装 ( Apache Felixなど) を使用すると、jar プラグインをアプリケーションにロードできます。これは、たとえばEclipseプラグインがどのように機能しているかです。(Atlassian は、Jira/Confluence/etc プラグインにもこの OSGI メカニズムを使用しています)。

OSGI は、プラグイン可能なプラグイン システムが必要な場合に遭遇する多くの問題を処理します。

たとえば、これは私がやっている方法です:

public ChannelListener init() {
    private ChannelListener listener = new ChannelListener();
    logger.info("Initializing Felix...");
    felix = new Felix(getConfig());

    try {
        felix.start();
    } catch (BundleException e) {
        logger.error("Error while initializing Felix", e);
        throw new RuntimeException(e);
    }

    try {
        // On the next line, you are registering a listener that will listen for all 
        //Log implementations service registration.
        felix.getBundleContext().addServiceListener(listener, "(objectClass=com.company.automation.service.Log)");
    } catch (InvalidSyntaxException e) {
        logger.error("Error while registering service listener", e);
    }
    listener.start(felix.getBundleContext());

    startAllBundlesInDirectory(BUNDLE_DIRECTORY, felix.getBundleContext());
    return listener;
}

private void startAllBundlesInDirectory(String directory, BundleContext context) {
    File bundleFolder = new File(directory);
    File[] bundleFilesList = bundleFolder.listFiles((dir, name) -> name.endsWith(".jar"));

    List<Bundle> installedBundles = new ArrayList<>();
    logger.info("Installing {} bundles in {}.", bundleFilesList.length, directory);
    for(File bundleFile : bundleFilesList) {
        logger.info("Installing {}", bundleFile.getName());
        try {
            installedBundles.add(context.installBundle("file:" + directory + bundleFile.getName()));
        } catch (BundleException e) {
            logger.error("Error while installing bundle {}{}", directory, bundleFile.getName(), e);
        }
    }

    for(Bundle bundle : installedBundles) {
        try {
            bundle.start();
        } catch (BundleException e) {
            logger.error("Error while starting bundle {}{}", directory, bundle.getSymbolicName(), e);
        }
    }
}
于 2016-10-27T12:59:31.283 に答える