在我的库代码中,我使用JAXB从XML文件加载类名,以便稍后使用Class.forName()
实例化它们。一个虚构的例子来说明这个案例:
public void libraryMethod() throws Exception {
List<String> classNames = loadClassNamesFromXML();
for (String className : classNames) {
Class.forName(className).newInstance().doThings();
}
}
现在,一些用户使用OSGi来配置他们的应用程序,并且他们使用与使用我的XML结构配置的类不同的类加载器加载我的库。这意味着加载可能会失败,因为无法找到类。
有没有更可靠的方法来加载这些类?或者有没有其他方法来配置这些实例?我愿意接受以下建议:
public void libraryMethod() throws Exception {
// Spring does things like this:
List<SomeType> instances = loadInstancesFromXML();
for (SomeType instance : instances) {
instance.doThings();
}
}
一些限制:
答案 0 :(得分:3)
如果您希望您的库灵活并在OSGi和非OSGi环境中工作,您应该允许用户提供他们自己的ClassLoader,或让他们告诉您的库他们有哪些类名。阅读Neil Bartlett blog post。
原始链接返回404.您可以访问Wayback Machine.
上的文章答案 1 :(得分:2)
感谢您的解释。 Spring在OSGi中不会让这更容易。您不能简单地从未导入的包中注入实现类。在OSGi中,您通常使用OSGi服务来注入源自bundle之外的实现,并且在编译时您不知道。
因此,您的用户将实现您指定的接口并将其实现发布为OSGi服务。然后,您可以选择所有此类服务,或让用户在xml配置中为其服务指定ldap过滤器。
这种方法的优点是您不必加载类并关心类加载器。所以这是OSGi中推荐的方法。如果你想在OSGi内部和外部使用相同的解决方案Ivan的方法是指定一个classloader + classname是另一种选择。
答案 2 :(得分:2)
通常,在OSGi中,您应该使用服务。 Class.forName / XML配置如此受欢迎的原因是只有一个类可以获得控制权。要配置其余部分,需要知道要初始化/调用的类。
在OSGi中,这个问题不存在,因为每个模块(bundle)(可以)通过声明性服务(或通过激活器以旧式方式)获得控制权。所以在OSGi中你有一个点对点模型。任何人都可以注册服务并依赖其他服务。
因此,不是指定类名并假设它们是全局唯一的(它们不在大型系统中),而是使用服务而不是离开Java编译器要容易得多;这些类名非常容易出错。通常,这意味着您通常只需注册您的服务并等待被调用,因为无需初始化您的客户端。但是,白板模式可以解决您想要了解客户端的情况(使用bndtools和bnd注释):
“服务器”
@Component
public class MyLib {
@Reference(type='*')
void addSomeType(SomeType st ) {
st.doThings();
}
}
客户
@Component
public class MyClient implements SomeType {
public void doThings() { ... }
}
希望这有帮助。
答案 3 :(得分:1)
JDBC4驱动程序包含jar中的META-INF / services / java.sql.Driver,它使用ServiceProvider机制向JVM注册Driver实现(请参阅java.util.ServiceLoader javadocs)。在类路径上使用驱动程序将自动注册驱动程序,从而无需使用Class.forName。相反,应用程序代码使用ServiceLoader.load来发现已注册的驱动程序。其他配置可以使用相同的机制。也许可以使用类似的东西?顺便说一句,当使用服务提供者机制注册自己的实现时,使用类似spi的注释看起来非常方便。