[英]ServiceLoader using ClassLoader pointing to different path
幾天以來一直在嘗試此操作,因此無法正常工作!
我正在嘗試構建一個可插入的Java應用程序,可以在其中從命令行運行它,並在單獨的文件夾中提供插件(罐子)。 看來ServiceLoader
可以滿足我的要求,但是我認為我需要一個特殊的情況,即jar不屬於類路徑,而它們存儲在不同的位置,因此,我需要使用ClassLoder
將其URL指向此位置。文件系統路徑。
我想提供給主應用程序的插件之一是帶有一些自定義功能的日志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);
}
}
=================
調整了項目結構,如下所示,但仍然無效:
它不起作用,因為它不是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.Log
而不是com.company.dep.automation.pluggable.Log
您的Main
班級,那么一切都會正常。
關於應用程序的“可插拔”部分以及將jars加載到文件夾中,而不是重新發明輪子,也許您可以看一下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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.