我正在尝试为我的应用程序创建一个插件系统,我想从简单的东西开始.每个插件都应该打包在.jar文件中并实现SimplePlugin
接口:
package plugintest;
public interface SimplePlugin {
public String getName();
}
Run Code Online (Sandbox Code Playgroud)
现在我创建了一个SimplePlugin
包装在.jar中的实现,并将其放在主应用程序的plugin /子目录中:
package plugintest;
public class PluginTest implements SimplePlugin {
public String getName() {
return "I'm the plugin!";
}
}
Run Code Online (Sandbox Code Playgroud)
在主应用程序中,我想获得一个实例PluginTest
.我尝试了两种方法,都使用了java.util.ServiceLoader
.
1.动态扩展类路径
这使用已知的hack在系统类加载器上使用反射来避免封装,以便添加URL
类路径.
package plugintest.system;
import plugintest.SimplePlugin;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;
public class ManagePlugins {
public static void main(String[] args) throws IOException {
File loc = new File("plugins");
extendClasspath(loc);
ServiceLoader<SimplePlugin> sl …
Run Code Online (Sandbox Code Playgroud) 在具有多个ClassLoader的环境中使用ServiceLoader的最佳实践是什么?文档建议在初始化时创建并保存单个服务实例:
private static ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
Run Code Online (Sandbox Code Playgroud)
这将使用当前上下文类加载器初始化ServiceLoader.现在假设此片段包含在使用Web容器中的共享类加载器加载的类中,并且多个Web应用程序想要定义自己的服务实现.这些不会在上面的代码中被提取,甚至可能使用第一个webapps上下文类加载器初始化加载器并向其他用户提供错误的实现.
始终创建新的ServiceLoader似乎是浪费性能,因为它必须每次枚举和解析服务文件.编辑:这甚至可能是一个很大的性能问题,如关于java的XPath实现的答案所示.
其他库如何处理这个?他们是否为每个类加载器缓存实现,他们是否每次都重新分析它们的配置,还是只是忽略了这个问题而只适用于一个类加载器?
我尝试使用Java ServiceLoader来查找实现特定接口的所有类,如下所示:
loader = ServiceLoader.load(Operation.class);
try {
for (Operation o : loader) {
operations.add(o);
}
} catch (ServiceConfigurationError e) {
LOGGER.log(Level.SEVERE, "Uncaught exception", e);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,当我在调试模式下运行Eclipse时,ServiceLoader找不到任何类.我觉得我错过了一个微不足道的观点......
作为对依赖性过敏的人,我什么时候会使用类似OSGi而不是内置的java 6 http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html(我想要的)让插件罐子掉进去).
(仅供参考,这是一个scala应用程序,对任何建议持开放态度,ServiceLoader非常接近我想要的).
我有一个遗留Java应用程序,其代码类似于此
ServiceLoader.load(SomeInterface.class)
Run Code Online (Sandbox Code Playgroud)
我想为这段代码提供SomeInterface的模拟实现.我使用mockito模拟框架.
不幸的是我无法更改遗留代码,我不希望静态添加任何内容(例如,向META-INF添加内容).
在测试中是否有一种简单的方法可以做到这一点,即.在测试的运行时?
我是java和android开发的新手并且学习我试图从应用程序开始收集像munin那样的统计和信息.我试图能够在我的应用程序中加载"插件".这些插件已经在应用程序中,但我不想单独调用它们,但能够迭代它们.我试图使用serviceloader,但永远不会将META-INF /服务放入我的apk中.所以我想知道是否有可能在android上使用serviceloader谢谢
编辑:我问的是java.util.ServiceLoader,我认为它应该,但我无法弄清楚如何将我的服务文件夹放到META-INF上APK
这是一个更为常见的问题:我使用的是xstream和woodstox,woodstox附带了一个服务提供程序,用于注册com.ctc.wstx.stax.WstxOutputFactory的woodstox jar中的javax.xml.stream.XMLOutputFactory.我想提供自己的javax.xml.stream.XMLOutputFactory,并且在类路径中仍然有woodstox jar.我知道我可以提供我自己的系统属性javax.xml.stream.XMLOutputFactory,但我正试图从我们的开发团队中解脱麻烦,并在我的jar中使用服务文件或者在我的战争中使用META -INF/services文件夹.查看javax.xml.stream.FactoryFinder的代码如何确保我的META-INF/services/javax.xml.stream.XMLOutputFactory文件将是FactoryFinder使用的文件?
我们使用xstream和camel,但找不到将工厂注入XStreamDataFormat的方法
我试图理解 Java 的ServiceLoader
概念、工作机制和具体用例,但发现官方文档太抽象和混乱。
首先,文档概述了服务和服务提供商。服务是一组接口和抽象类,封装在一个 jar 档案(API 库)中。服务提供者是一组实现或扩展 API 的类,封装在一个不同的 jar 文件(提供者库)中。
到目前为止一切顺利,但随后文档变得混乱。
出于加载的目的,服务由单一类型表示,即单一接口或抽象类。(可以使用具体类,但不建议这样做。)给定服务的提供者包含一个或多个具体类,这些类使用特定于提供者的数据和代码扩展该服务类型。提供者类通常不是整个提供者本身,而是一个代理,它包含足够的信息来决定提供者是否能够满足特定请求以及可以按需创建实际提供者的代码。提供者类的细节往往是高度特定于服务的;没有任何一个类或接口可以统一它们,所以这里没有定义这样的类型。
那么实际上Service type和Provider class 是什么?我的印象是,服务类型是API 库中的一个门面,提供者类是提供者库中这个门面接口的实现,即ServiceLoader
实际加载的类。这样对吗?但对我来说,所有组件如何联系在一起仍然没有多大意义。
提供者类作为代理来决定提供者是否能够满足特定请求以及可以按需创建实际提供者的代码是什么意思?无法在何处定义统一类型?基本上所有这一段都令人困惑,我想通过一个具体的例子听到更容易理解的解释。
然后关于提供者配置文件...
通过在资源目录 META-INF/services 中放置一个提供者配置文件来识别服务提供者。该文件的名称是服务类型的完全限定二进制名称。该文件包含具体提供者类的完全限定二进制名称列表,每行一个...
命名特定提供程序的配置文件不必与提供程序本身位于同一 jar 文件或其他分发单元中。提供者必须可以从最初查询以定位配置文件的同一个类加载器访问;请注意,这不一定是实际加载文件的类加载器。
这是否意味着对于服务类型为 org.foo.BarServiceType 的 API,在类路径中必须存在具有实现此类型的类的提供程序 jar和 META-INF/services/org.foo.BarServiceType
列出此提供程序类的命名提供程序配置文件,所有这些都可以通过Classloader
加载ServiceLoader
查找的相同访问并在 API 上绑定提供者?
从类加载器的角度来看,可访问意味着提供者配置文件和提供者库可以在包的外部提供,在层次结构的上层,即从容器或其他中间件。
提供者配置文件列出了提供者类,并且可能捆绑在提供者包中(如果捆绑了为什么它会列出多个类?)或来自外部。但是哪种方法更常见:在提供者之间提供配置文件,还是从 API 库本身提供列出一组支持的提供者的文件?还是后者是一种误解?
最后关于 ServiceLoader
在哪里ServiceLoader
实际实例化并调用以加载服务提供者?这是否发生在API 库提供的工厂方法中?例如,不LoggingFactory.getLogger(clazz)
的SLF4J内部委托给ServiceLoader
,它使用反射来读取提供者配置文件并加载服务?
服务加载机制如何处理存在多个提供者及其配置文件的情况,或者有提供者配置文件条目但没有类本身的情况?
ServiceLoader
日志框架之外的其他一些具体用例是什么?它在Java …
我有一个相当大的Java ee应用程序,它具有执行大量xml处理的巨大类路径。目前,我正在尝试加快某些功能的速度,并通过采样分析器定位慢速代码路径。
我注意到的一件事是,特别是我们在其中调用类似代码的部分TransformerFactory.newInstance(...)
非常慢。我跟踪下来到FactoryFinder
方法findServiceProvider
始终创建一个新的ServiceLoader
实例。在ServiceLoader
javadoc中,我发现了有关缓存的以下说明:
提供商的位置很懒,即按需实例化。服务加载器维护到目前为止已加载的提供者的缓存。每次迭代器方法的调用都会返回一个迭代器,该迭代器首先以实例化顺序生成高速缓存的所有元素,然后懒惰地定位和实例化任何剩余的提供程序,依次将每个提供程序添加到高速缓存中。可以通过reload方法清除缓存。
到目前为止,一切都很好。这是OpenJDKs FactoryFinder#findServiceProvider
方法的一部分:
private static <T> T findServiceProvider(final Class<T> type)
throws TransformerFactoryConfigurationError
{
try {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} catch(ServiceConfigurationError e) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
每一通findServiceProvider
电话ServiceLoader.load
。每次都会创建一个新的 ServiceLoader。这样,似乎根本没有使用ServiceLoaders缓存机制。每个调用都会扫描类路径以查找请求的ServiceProvider。
我已经尝试过的:
javax.xml.transform.TransformerFactory
来指定特定的实现。这样,FactoryFinder不会使用ServiceLoader进程及其超快的速度。遗憾的是,这是jvm范围的属性,会影响在我的jvm中运行的其他java进程。例如,我的应用程序随Saxon一起提供并且应该使用,但com.saxonica.config.EnterpriseTransformerFactory …
我一直试图将我们的Activiti实现重构为使用CDI但遇到了许多问题.我已经花了太多时间试图解决这个问题,但我不能放手......我想我已经把问题归结为现在,建立一个干净的结构化战争而不涉及Activiti并且能够重现我认为是主要问题.
基本上我有jar1和jar2,通过包含META-INF/beans.xml启用了CDI.两个jar都在META-INF/services/test中指定一个类.Test指向各个jar的本地实现.jar1取决于jar2.此外,两个jar都指向javax.enterprise.inject.spi.Extension的实现,触发方案.在Extension的每个实现中,我有一个方法,如:
public void afterDeploymentValidation(
@Observes AfterDeploymentValidation event, BeanManager beanManager) {
System.out.println("In jar1 extension");
ServiceLoader<TheTest> loader = ServiceLoader.load(TheTest.class);
Iterator<TheTest> serviceIterator = loader.iterator();
List<TheTest> discoveredLookups = new ArrayList<TheTest>();
while (serviceIterator.hasNext()) {
TheTest serviceInstance = (TheTest) serviceIterator.next();
discoveredLookups.add(serviceInstance);
System.out.println(serviceInstance.getClass().getName());
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我的问题是,ServiceLoader
在运行WebLogic12c时,两种情况都没有看到任何实现.相同的代码在Jboss 7.1.1和Glassfish中都运行得非常好,列出了test.TheTest接口的两个实现.
假设这确实是WebLogic 12c中的一个问题或我做错了什么是公平的吗?请记住,我只是想模仿我们在使用Activiti时使用的生产设置.
此致,/ Petter
serviceloader ×10
java ×9
classloader ×2
jar ×2
android ×1
cdi ×1
classpath ×1
frameworks ×1
meta-inf ×1
mockito ×1
osgi ×1
stax ×1
weblogic ×1
woodstox ×1