温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

什么是ServiceLoader解耦服务

发布时间:2021-06-28 17:22:23 来源:亿速云 阅读:138 作者:chen 栏目:编程语言

本篇内容介绍了“什么是ServiceLoader解耦服务”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

ServiceLoader解耦服务

背景

SPI,全称Service Provider Interfaces,服务提供接口。是Java提供的一套供第三方实现或扩展使用的技术体系。主要通过解耦服务具体实现以及服务使用,使得程序的可扩展性大大增强,甚至可插拔。

基于服务的注册与发现机制,服务提供者向系统注册服务,服务使用者通过查找发现服务,可以达到服务的提供与使用的分离,甚至完成对服务的管理。

JDK中,基于SPI的思想,提供了默认具体的实现,ServiceLoader。利用JDK自带的ServiceLoader,可以轻松实现面向服务的注册与发现,完成服务提供与使用的解耦

完成分离后的服务,使得服务提供方的修改或替换,不会给服务使用方带来代码上的修改,基于面向接口的服务约定,提供方和使用方各自直接面向接口编程,而不用关注对方的具体实现。同时,服务使用方使用到服务时,也才会真正意义上去发现服务,以完成服务的初始化,形成了服务的动态加载

原理

  • ServiceLoader代码片段

  •  

  • 说明

外部使用时,往往通过load(Class<S> service, ClassLoader loader)load(Class<S> service)调用,最后都是在reload方法中创建了LazyIterator对象,LazyIteratorServiceLoader的内部类,实现了Iterator接口,其作用是一个懒加载的迭代器,在hasNextService方法中,完成了对位于META-INF/services/目录下的配置文件的解析,并在nextService方法中,完成了对具体实现类的实例化。

JDK的ServiceLoader通过返回一个Iterator对象能够做到对服务实例的懒加载 只有当调用iterator.next()方法时才会实例化下一个服务实例,只有需要使用的时候才进行实例化,具体实现读者可以去阅读源码进行研究,这也是其设计的亮点之一。

META-INF/services/,是ServiceLoader中约定的接口与实现类的关系配置目录,文件名是接口全限定类名,内容是接口对应的具体实现类,如果有多个实现类,分别将不同的实现类都分别作为每一行去配置。解析过程中,通过LinkedHashMap<String,S>数据结构的providers,将已经发现了的接口实现类进行了缓存,并对外提供的iterator()方法,方便外部遍历。

总体上,ServiceLoader的一般实现与使用过程包含了服务接口约定服务实现服务注册服务发现与使用这四个步骤。

应用

r2dbc-mariadb实际也是基于r2dbc-spi的方式实现服务解耦

  • 服务接口约定: r2dbc-spi

  • 服务实现:r2dbc-mariadb对r2dbc-spi的实现

  • 服务注册:r2dbc-mariadb包中META-INF.service文件


  • 服务发现:在r2dbc-spi中创建连接工厂的方法

    public static ConnectionFactory find(ConnectionFactoryOptions connectionFactoryOptions) {
        Assert.requireNonNull(connectionFactoryOptions, "connectionFactoryOptions must not be null");

        for (ConnectionFactoryProvider provider : loadProviders()) {
            if (provider.supports(connectionFactoryOptions)) {
                return provider.create(connectionFactoryOptions);
            }
        }

        return null;
    }

    private static ServiceLoader<ConnectionFactoryProvider> loadProviders() {
            return AccessController.doPrivileged((PrivilegedAction<ServiceLoader<ConnectionFactoryProvider>>) () -> ServiceLoader.load(ConnectionFactoryProvider.class,
                ConnectionFactoryProvider.class.getClassLoader()));
        }

之所以ServiceLoader能够发现ZenithConnectionFactoryProvider,是因为在r2dbc-zenith的META-INF.service文件中添加响应的类路径声明(注册自己)以供ServerLoader扫描。

其他应用,如:jdbc-driver

“什么是ServiceLoader解耦服务”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI