有没有用Class.forName()加载类的替代方法?

时间:2012-07-14 13:04:23

标签: java osgi classloader

在我的库代码中,我使用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 个答案:

答案 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的注释看起来非常方便。