ServiceLoader是否真的动态加载提供程序?

时间:2018-03-18 21:40:50

标签: java java-9

我最近发现矛盾的文档是否服务加载程序会在启动后找到添加到模块路径的提供程序。

ServiceLoader::reload

public void reload​()
     

清除此加载程序的提供程序缓存,以便重新加载所有提供程序。   在调用此方法之后,迭代器或流方法的后续调用将从头开始懒惰地定位提供程序(并在迭代器的情况下实例化),就像新创建的服务加载程序一样。

     

此方法适用于可以将新服务提供程序安装到正在运行的Java虚拟机中的情况。

这清楚地表明服务分辨率是完全动态的。

另一方面,ModuleFinder::findAll与之相矛盾。
" ModuleFinder用于在解析或服务绑定期间查找模块。" - Javadoc

Set<ModuleReference> findAll​()
     

返回此查找程序可以找到的所有模块引用的集合。   ModuleFinder提供了它所找到的模块的一致视图。 如果多次调用findAll,那么每次都会返回相同的(等于)结果。对于返回集合中的每个ModuleReference元素,保证find会在调用时找到ModuleReference来查找该模块

根据这句话,解决方案在模块层创建时已得到修复,实际上是预期的,因为整个Java平台模块系统是设计上的静态。如果新的提供商需要其他模块,则必须修改现有的模块图。

所以我的问题是:第一个引用是否来自Java 8 Javadoc的文档,还是可能存在我可以动态添加新提供程序的情况?

我将在此证明模块查找器文档是正确的:

班级com.service.Service

package com.service;

import java.util.ServiceLoader;
import java.util.stream.Collectors;

public interface Service {

    public static void main(String[] args) throws InterruptedException {
        ServiceLoader<Service> loader = ServiceLoader.load(Service.class);

        for (int i = 0; i < 5; i++) {
            System.out.print("Attempt " + (i + 1) + ": ");
            System.out.println(loader
                            .stream()
                            .map(ServiceLoader.Provider::type)
                            .map(Object::toString)
                            .collect(Collectors.joining(", ")));

            Thread.sleep(5000);
            loader.reload();
        }
    }
}

module-info

module service {
    exports com.service;
    uses com.service.Service;
}

在另一个模块中,类com.provider.Provider

package com.provider;

import com.service.Service;

public class Provider implements Service {

}

module-info

module provider {
    exports com.provider;
    requires service;
    provides com.service.Service with com.provider.Provider;
}

这是一个实时GIF,当我第一次在模块路径中没有提供者的情况下运行它时会发生什么。在第二次运行时,提供程序已经存在,我将尝试在运行时删除它。

console

1 个答案:

答案 0 :(得分:4)

服务提供程序API在Java类加载器之上工作,默认情况下它们不是动态的。类路径在JVM启动时确定,然后不会更新:您尝试删除的JAR由JVM打开,并且在关闭之前不会释放。如果您需要一些不同的行为,则需要使用自定义类加载器,例如JEE应用程序服务器用于部署Web应用程序或OSGi实现中的类加载器。