ServiceLoader是否真的动态加载提供程序? [英] Does ServiceLoader really load providers dynamically?

查看:98
本文介绍了ServiceLoader是否真的动态加载提供程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近发现了相互矛盾的文档,表明服务加载程序是否会在引导后找到添加到模块路径的提供程序.

I recently found contradictory documentation whether service loader will locate providers added to the module path after boot.

ServiceLoader::reload :

public void reload​()

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

Clear this loader's provider cache so that all providers will be reloaded. After invoking this method, subsequent invocations of the iterator or stream methods will lazily locate providers (and instantiate in the case of iterator) from scratch, just as is done by a newly-created service loader.

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

明确表明服务解析是完全动态的.

Which clearly indicates that the service resolution is completely dynamic.

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

From the other hand ModuleFinder::findAll contradicts it.
"A ModuleFinder is used to find modules during resolution or service binding." — Javadoc

Set<ModuleReference> findAll​()

返回此查找器可以找到的所有模块引用的集合. ModuleFinder提供了所定位模块的一致视图. 如果findAll被多次调用,则每次将返回相同(等于)的结果.对于返回集中的每个ModuleReference元素,如果调用findfind来查找该模块,则可以保证find可以找到ModuleReference.

Returns the set of all module references that this finder can locate. A ModuleFinder provides a consistent view of the modules that it locates. If findAll is invoked several times then it will return the same (equals) result each time. For each ModuleReference element in the returned set then it is guaranteed that find will locate the ModuleReference if invoked to find that module.

根据此引用,分辨率固定在模块层创建上,这实际上是期望的,因为整个Java平台模块系统在设计上是静态的.如果新的提供程序需要其他模块,则必须修改现有的模块图.

According to this quote the resolution is fixed at module layer creation which is actually expected as the whole Java Platform Module System is static by design. If new providers would've require other modules it would have to modify the existing module graph.

所以我的问题是:

So my question is: Is the first quote left-over docs from Java 8 Javadoc, or there might really be cases where I can add new providers dynamically?

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

Here I'm going to prove that the module finder docs is correct:

Class 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:

In a different module, class 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,当我第一次在模块路径中没有提供程序的情况下运行它时会发生什么.在第二次运行时,提供程序已经存在,我将尝试在运行时将其删除.

Here's a live GIF what happens when I first run it without the provider in the modulepath. On the second run the provider is already there, I'll try to remove it while runnning.

推荐答案

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

The service provider API works on top of Java class loaders, which are not dynamic by default. The class path is determined on JVM startup and then will not be updated: the JAR you are trying to delete, is opened by JVM, and will not be released until the shutdown. If you need some different behavior, you'll need to use a custom class loader, like the ones used by JEE application servers for the deployment of webapps or the class loaders in OSGi implementations.

这篇关于ServiceLoader是否真的动态加载提供程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆