4

在我的库代码中,我使用 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();
  }
}

一些限制:

  • 从库的角度来看,这些实例的生命周期并不重要。如果他们有(用户)状态,我的图书馆不会注意到。
  • 我想在这个库中保持简单,所以我想避免在配置框架上创建外部依赖项,例如 spring。所以我只对标准 JDK 6+ 发行版可以实现的解决方案感兴趣。
  • 我真的很想保留我的简单 XML 配置文件(对 XML 结构稍作调整是可以的)。
4

4 回答 4

3

如果您希望您的库灵活并在 OSGi 和非 OSGi 环境中工作,您应该允许用户提供他们自己的 ClassLoader,或者让他们告诉您的库他们有哪些类名。阅读Neil Bartlett 博客文章

原始链接返回 404。您可以访问Wayback Machine 上的文章。

于 2012-07-14T16:30:34.783 回答
2

感谢您的解释。在 OSGi 中,Spring 不会让这变得更容易。您不能简单地从未导入的包中注入实现类。在 OSGi 中,您通常使用 OSGi 服务来注入源自您的包之外并且在编译时您不知道的实现。

因此,您的用户将实现您指定的接口并将其实现发布为 OSGi 服务。然后,您可以选择所有此类服务,或者让用户在 xml 配置中为他的服务指定一个 ldap 过滤器。

这种方法的优点是您不必加载类并关心类加载器。所以这是 OSGi 中推荐的方式。如果您想在 OSGi 内部和外部使用相同的解决方案,那么指定类加载器 + 类名的方法是另一种选择。

于 2012-07-14T21:06:36.287 回答
2

通常,在 OSGi 中您应该使用服务。Class.forName/XML 配置如此流行的原因是只有一个类获得控制权。要配置其余部分,它需要知道要初始化/调用的类。

在 OSGi 中,这个问题不存在,因为每个模块(包)(可以)通过声明式服务(或以老式方式通过激活器)获得控制。所以在 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() { ... }
}

希望这可以帮助。

于 2012-07-16T13:58:54.980 回答
1

JDBC4 驱动程序在 jar 中包含 META-INF/services/java.sql.Driver,它使用 ServiceProvider 机制向 JVM 注册驱动程序实现(参见java.util.ServiceLoader javadocs)。将驱动程序放在类路径上将自动注册驱动程序,无需使用 Class.forName。相反,应用程序代码使用 ServiceLoader.load 来发现已注册的驱动程序。相同的机制可用于其他配置。也许可以使用类似的东西?顺便说一句,在使用 Service Provider 机制注册自己的实现时,使用像spi这样的注解看起来很方便。

于 2012-07-14T19:29:13.187 回答