我是 OSGi 的新手,很快就被它的复杂性弄得不知所措。我相信这应该相当简单,但我还没有找到一个完整的工作示例来说明我正在努力实现的目标。
我有一个包含服务集合的 Java 类 Foo
。这些服务需要根据特定于 Foo
的特定实例的值进行过滤。 Foo
可以有多个实例,但每个实例都应该有自己的一组过滤服务。
为了说明,请考虑以下示例(受 Apache Felix tutorials 启发):
public interface DictionaryService {
public boolean check(String word);
}
@Component(property = "language=en")
public class EnglishDictionaryService implements DictionaryService {
private static final String[] WORDS = {"hi", "hello" /*...*/};
@Override
public boolean check(String word) {
if (word == null || word.isEmpty()) {
return true;
}
// super inefficient but you get the gist
return Arrays.stream(WORDS).anyMatch(entry -> word.equalsIgnoreCase(entry));
}
}
@Component(property = "language=en")
public class TexanDictionaryService implements DictionaryService {
private static final String[] WORDS = {"howdy" /*...*/};
//...
}
@Component(property = "language=en")
public class AustralianDictionaryService implements DictionaryService {
private static final String[] WORDS = {"g'day" /*...*/};
//...
}
@Component(property = "language=es")
public class SpanishDictionaryService implements DictionaryService {
private static final String[] WORDS = {"hola" /*...*/};
//...
}
@Component
public class SpellChecker {
@Reference
private volatile List<DictionaryService> dictionaryServices;
public SpellChecker(String language) {
// TODO: how to ensure my dictionaryServices match the given language code?
// dictionaryServices.target = "(language=" + language + ")"
}
public boolean check(String word) {
if (word == null || word.isEmpty()) {
return true;
}
List<DictionaryService> ds = dictionaryServices;
if (ds == null || ds.isEmpty()) {
return false;
}
return ds.stream().anyMatch(dictionary -> dictionary.check(word));
}
}
public static void main(String[] args) {
SpellChecker englishChecker = new SpellChecker("en");
SpellChecker spanishChecker = new SpellChecker("es");
// do stuff
}
看完several StackExchange posts还有一些other articles ,这似乎可以使用 ConfigurationAdmin
来完成。但是,尚不清楚应该在何处以及如何使用 ConfigurationAdmin
,尤其是在声明式服务方面。我还阅读并重读了 Configuration Admin Service Specification ,但我正在努力应用这些概念。
谁能填补我理解上的空白?
提前致谢!
编辑
Christian's answer帮助我以不同的方式思考声明式服务。当我回顾我的研究时,我遇到了 Alan Hohn's blog posts on DZone再次。不幸的是,他似乎从未完成 promise 涵盖使用 DS 进行服务查找的系列文章。然而,他的example source code包含以下内容:
public String greet(String language) {
BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
String filter = "(language=" + language + ")";
// Get ServiceReference(s) from OSGi framework, filtered for the specified value
ServiceReference[] refs = null;
try {
refs = context.getServiceReferences(Greeter.class.getName(), filter);
if (null != refs) {
Greeter greeter = (Greeter)context.getService(refs[0]);
return greeter.greet();
}
} catch (InvalidSyntaxException e) {
LOGGER.error("Invalid query syntax", e);
}
LOGGER.warn("No plugins found, making the default greeting");
return "Hello from the greeter manager!";
}
这看起来是一个可行的解决方案,但它似乎没有使用 DS。这种方法有什么特别的考虑吗?我在 SO 和其他地方看到很多帖子声称 DS 是 BundleContext#getServiceReferences
的 Elixir ,所以我很好奇是否/如何重构它以使用 DS。
最佳答案
您在 main 中的代码没有意义。
如果您使用 new
关键字创建(声明性服务)DS 组件的实例,则不会执行整个 DS 逻辑。实际上,在 OSGi 中,您根本不使用 main
方法……也许是为了启动框架而不是为了您自己的逻辑。
您可以通过创建一个使用它的 shell 命令或创建一个使用它的 http 白板服务来访问您的拼写检查器。
要在 SpellChecker
中设置服务引用过滤器,您可以使用如下配置:
pid:拼写检查器的完全限定名称
dictionaryServices.target=(language=en)
这会将 SpellChecker
设置为仅使用英语词典。
更多关于DS的小技巧可以引用 https://liquid-reality.de/2016/09/26/hints-ds.html
关于java - 使用声明式服务根据属性动态选择 OSGi 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55653320/