关于Java获取接口所有实现类的方式,可以采用以下三种方法:
方法一:利用Java SPI机制
Java SPI(Service Provider Interface)即服务提供商接口,是Java标准类库中的一种服务提供发现机制。利用Java SPI机制,我们可以很容易地获取到某个接口的所有实现类。具体操作步骤如下:
- 定义接口
MyService
:
java
public interface MyService {
void doSomething();
}
- 实现接口
MyService
并在src/main/resources/META-INF/services
文件夹下创建一个名为com.myservice.MyService
的普通文本文件,里面写上实现类的全限定名,如下:
com.example.service.impl.MyServiceImpl1
com.example.service.impl.MyServiceImpl2
- 通过以下代码获取
MyService
接口的所有实现类:
java
import java.util.ServiceLoader;
public class Main {
public static void main(String[] args) {
ServiceLoader<MyService> myServices = ServiceLoader.load(MyService.class);
for (MyService myService : myServices) {
myService.doSomething();
}
}
}
以上就是利用Java SPI机制获取接口所有实现类的方式。
方法二:扫描指定包下的类
这种方式相对于SPI机制来说,更加灵活,可以实现扫描指定包下的所有类,并且只要是某个接口的实现类就可以获取到。具体操作步骤如下:
- 定义接口
MyService
和实现类MyServiceImpl1
和MyServiceImpl2
:
java
public interface MyService {
void doSomething();
}
public class MyServiceImpl1 implements MyService {
@Override
public void doSomething() {
System.out.println("MyServiceImpl1.doSomething()");
}
}
public class MyServiceImpl2 implements MyService {
@Override
public void doSomething() {
System.out.println("MyServiceImpl2.doSomething()");
}
}
- 创建一个扫描指定包下的类的工具类
ClassLoaderUtils
:
java
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class ClassLoaderUtils {
public static List<Class<?>> getClassListByAnnotation(ClassLoader classLoader, String packageName, Class<? extends Annotation> annotationClass) throws IOException, ClassNotFoundException {
List<Class<?>> classList = new ArrayList<>();
String resourceName = packageName.replaceAll("\\.", "/");
Enumeration<URL> urls = classLoader.getResources(resourceName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
String packagePath = url.getPath();
findClassInPackageByFile(packageName, "", packagePath, annotationClass, classList);
} else if ("jar".equals(protocol)) {
//处理JAR文件
System.err.println("暂未处理JAR文件类型");
}
}
return classList;
}
private static void findClassInPackageByFile(String packageName, String currentPackagePath, String packagePath, Class<? extends Annotation> annotationClass, List<Class<?>> classList) throws ClassNotFoundException {
File[] files = new File(packagePath).listFiles(pathname -> pathname.isDirectory() || pathname.getName().endsWith(".class"));
for (File file : files) {
if (file.isDirectory()) {
findClassInPackageByFile(packageName, currentPackagePath + file.getName() + "/", file.getAbsolutePath(), annotationClass, classList);
} else {
String className = file.getName().substring(0, file.getName().length() - 6);
Class<?> clazz = Class.forName(packageName + "." + currentPackagePath + className);
if (annotationClass == null || clazz.isAnnotationPresent(annotationClass)) {
classList.add(clazz);
}
}
}
}
}
- 通过以下代码获取指定包下实现了
MyService
接口的所有类:
java
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String packageName = "com.example.service.impl";
ServiceLoader<MyService> myServices = ServiceLoader.load(MyService.class);
List<Class<?>> classes = ClassLoaderUtils.getClassListByAnnotation(Thread.currentThread().getContextClassLoader(), packageName, null);
for (Class<?> clazz : classes) {
if (Arrays.asList(clazz.getInterfaces()).contains(MyService.class)) {
myServices.reload();
for (MyService myService : myServices) {
if (clazz.equals(myService.getClass())) {
try {
myService.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
以上就是通过扫描指定包下的类获取接口所有实现类的方式。
以上两种方式都可以获取到指定接口的所有实现类,根据具体情况,选择合适的方式即可。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java获取接口所有实现类的方式详解 - Python技术站