动态加载遵循接口的类

Dan*_*nny 4 java reflection interface

我有几个实现两个接口的类.它们都实现了BaseInterface和其他一些特定于它们的接口.

我希望能够使用下面的loadClass方法来实例化.properties文件中引用的类,并调用它们都包含的公共方法(因为它们实现了BaseInterface).

public interface BaseInterface {
    public void doBase();
}

public interface SpecificInterface extends BaseInterface {
    public void doSpecific();
}

public class SpecificClass implements SpecificInterface {
    public void doBase() { ... }

    public void doSpecific() { ... }
}

public class LoadClass() {
    private PropertiesLoader propertiesLoader = new PropertiesLoader();

    public <C extends BaseInterface> C loadClass(String propertyName) {
        Class<C> theClass;

        // Load the class.
        theClass = propertiesLoader.getPropertyAsClass(propertyName);

        // Create an instance of the class.
        C theInstance = theClass.newInstance();

        // Call the common method.
        theInstance.doBase();

        return theInstance;
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我运行代码时:

loadClassInstance.loadClass("SpecificClass");
Run Code Online (Sandbox Code Playgroud)

我得到以下异常:

Exception in thread "main" java.lang.ClassCastException:
SpecificClass cannot be cast to BaseInterface
at LoadClass.loadClass
Run Code Online (Sandbox Code Playgroud)

有什么想法我会如何解决这个问题?

非常感谢,Danny

Bri*_*ian 14

Java的服务提供程序接口(SPI)库允许您根据它们实现的接口动态加载类,并且所有这些都是通过使用来完成的META-INF/services.

首先,你需要interface:

package com.example;

public interface SomeService {

    String getServiceId();

    String getDisplayName();
}
Run Code Online (Sandbox Code Playgroud)

然后,当您需要它们时,可以使用Java的ServiceLoader类加载它们,该类实现Iterable:

ServiceLoader<SomeService> loader = ServiceLoader.load(SomeService.class);
for (SomeService serv : loader) {
    System.out.println(serv.getDisplayName());
}
Run Code Online (Sandbox Code Playgroud)

然后,当您在类路径上有一个或多个实现类时,它们会自行注册META-INF/services.所以如果你有实现:

package com.acme;

public class SomeImplementation implements SomeService {

    // ...

    public SomeImplementation() { ... }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,此类需要一个默认的no-args构造函数,这不是可选的.

您可以通过在类META-INF/services路径中创建一个文件(例如在jar的根目录中)并使用以下属性在类加载器中注册它:

  1. 该文件的名称是接口的完全限定类名,在这种情况下,它是 com.example.SomeService
  2. 该文件包含一个以换行符分隔的实现列表,因此对于示例实现,它将包含一行:com.acme.SomeImplementation.

你走了,就是这样.如何构建项目将决定您放置META-INF/services内容的位置.Maven,Ant等都有办法解决这个问题.如果您在构建中添加这些文件时遇到任何问题,我建议您询问有关特定构建过程的其他问题.