【Java】ServiceLoader源码分析
时间: 2023-07-01 12:18:48 浏览: 138
Java的ServiceLoader是一个用于加载服务提供者的工具类。服务提供者是指实现了某个特定服务的类,它们通常会被打包成jar文件,并在应用程序运行时动态加载。
ServiceLoader的实现原理是基于Java SPI机制,它通过查找META-INF/services目录下的配置文件来加载服务提供者,配置文件的格式为:
```
com.example.MyService
```
其中,com.example.MyService是服务提供者的全限定类名。
接下来,我们来分析一下ServiceLoader的源码实现:
1. ServiceLoader的构造函数
```
private ServiceLoader(Class<S> service, ClassLoader loader) {
this.service = Objects.requireNonNull(service, "Service interface cannot be null");
this.loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
```
构造函数接收服务提供者的接口类和类加载器,然后进行初始化,并调用reload()方法加载服务提供者。
2. ServiceLoader的reload()方法
```
private void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
```
reload()方法会清空已加载的服务提供者,并创建一个新的LazyIterator对象。
3. ServiceLoader的iterator()方法
```
public Iterator<S> iterator() {
return new Iterator<S>() {
private final LazyIterator<S> knownProviders = lookupIterator;
private Iterator<S> serviceProviderIterator = Collections.emptyIterator();
public boolean hasNext() {
if (serviceProviderIterator.hasNext()) {
return true;
}
if (knownProviders.hasNext()) {
serviceProviderIterator = knownProviders.next().iterator();
return hasNext();
}
return false;
}
public S next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return serviceProviderIterator.next();
}
public void remove() {
serviceProviderIterator.remove();
}
};
}
```
iterator()方法会返回一个迭代器对象,用于遍历已加载的服务提供者。该迭代器内部维护了一个knownProviders对象和一个serviceProviderIterator对象。在遍历时,先判断serviceProviderIterator是否还有下一个元素,如果有则直接返回,否则就从knownProviders中加载下一个服务提供者,并将其迭代器赋值给serviceProviderIterator。
4. ServiceLoader的LazyIterator类
```
private static class LazyIterator<T> implements Iterator<T> {
Class<T> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<T> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
public boolean hasNext() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = "META-INF/services/" + service.getName();
if (loader == null) {
configs = ClassLoader.getSystemResources(fullName);
} else {
configs = loader.getResources(fullName);
}
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while (pending == null || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String cn = nextName;
nextName = null;
try {
return service.cast(Class.forName(cn, true, loader).newInstance());
} catch (ClassNotFoundException x) {
fail(service, "Provider " + cn + " not found");
} catch (Exception x) {
fail(service, "Provider " + cn + " could not be instantiated", x);
}
throw new Error();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
```
LazyIterator类实现了Iterator接口,它负责从配置文件中解析出服务提供者的类名,并进行实例化。在hasNext()方法中,首先判断nextName是否已经被赋值,如果是则直接返回true,否则就从配置文件中解析出下一个类名。在next()方法中,将nextName赋值给cn变量,然后通过反射加载并实例化服务提供者类,最后返回实例化对象。
以上就是ServiceLoader的源码实现分析。通过分析,我们可以了解到ServiceLoader的实现原理,以及如何通过配置文件来加载服务提供者。
阅读全文