Java是如何实现自己的SPI机制的? JDK源码(一)

注:该源码分析对应JDK版本为1.8

1 引言

这是【源码笔记】的JDK源码解读的第一篇文章,本篇我们来探究Java的SPI机制的相关源码。

2 什么是SPI机制

那么,什么是SPI机制呢?

SPI是Service Provider Interface 的简称,即服务提供者接口的意思。根据字面意思我们可能还有点困惑,SPI说白了就是一种扩展机制,我们在相应配置文件中定义好某个接口的实现类,然后再根据这个接口去这个配置文件中加载这个实例类并实例化,其实SPI就是这么一个东西。说到SPI机制,我们最常见的就是Java的SPI机制,此外,还有Dubbo和SpringBoot自定义的SPI机制。

有了SPI机制,那么就为一些框架的灵活扩展提供了可能,而不必将框架的一些实现类写死在代码里面。

那么,某些框架是如何利用SPI机制来做到灵活扩展的呢?下面举几个栗子来阐述下:

  1. JDBC驱动加载案例:利用Java的SPI机制,我们可以根据不同的数据库厂商来引入不同的JDBC驱动包;

  2. SpringBoot的SPI机制:我们可以在spring.factories中加上我们自定义的自动配置类,事件监听器或初始化器等;

  3. Dubbo的SPI机制:Dubbo更是把SPI机制应用的淋漓尽致,Dubbo基本上自身的每个功能点都提供了扩展点,比如提供了集群扩展,路由扩展和负载均衡扩展等差不多接近30个扩展点。如果Dubbo的某个内置实现不符合我们的需求,那么我们只要利用其SPI机制将我们的实现替换掉Dubbo的实现即可。

上面的三个栗子先让我们直观感受下某些框架利用SPI机制是如何做到灵活扩展的。

3 如何使用Java的SPI?

我们先来看看如何使用Java自带的SPI。先定义一个Developer接口

// Developer.java

package com.ymbj.spi;

public interface Developer {
    void sayHi();
}

再定义两个Developer接口的两个实现类:

// JavaDeveloper.java

package com.ymbj.spi;

public class JavaDeveloper implements Developer {

    @Override
    public void sayHi() {
        System.out.println("Hi, I am a Java Developer.");
    }
}
// PythonDeveloper.java

package com.ymbj.spi;

public class PythonDeveloper implements Developer {

    @Override
    public void sayHi() {
        System.out.println("Hi, I am a Python Developer.");
    }
}

然后再在项目resources目录下新建一个META-INF/services文件夹,然后再新建一个以Developer接口的全限定名命名的文件,文件内容为:

// com.ymbj.spi.Developer文件

com.ymbj.spi.JavaDeveloper
com.ymbj.spi.PythonDeveloper

最后我们再新建一个测试类JdkSPITest

// JdkSPITest.java

public class JdkSPITest {

    @Test
    public void testSayHi() throws Exception {
        ServiceLoader<Developer> serviceLoader = ServiceLoader.load(Developer.class);
        serviceLoader.forEach(Developer::sayHi);
    }
}

运行上面那个测试类,运行成功结果如下截图所示:

由上面简单的Demo我们知道了如何使用Java的SPI机制来实现扩展点加载,下面推荐一篇文章JAVA拾遗--关于SPI机制,通过这篇文章,相信大家对Java的SPI会有一个比较深刻的理解,特别是JDBC加载驱动这方面。

4 Java的SPI机制的源码分析

通过前面扩展Developer接口的简单Demo,我们看到Java的SPI机制实现跟ServiceLoader这个类有关,那么我们先来看下ServiceLoader的类结构代码:

// ServiceLoader实现了【Iterable】接口
public final class ServiceLoader<S>
    implements Iterable<S>{
    private static final String PREFIX = "META-INF/services/";
    // The class or interface representing the service being loaded
    private final Class<S> service;
    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;
    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;
    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
    // The current lazy-lookup iterator
    private LazyIterator lookupIterator;
    // 构造方法
    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }
	
    // ...暂时省略相关代码
    
    // ServiceLoader的内部类LazyIterator,实现了【Iterator】接口
    // Private inner class implementing fully-lazy provider lookup
    private class LazyIterator
        implements Iterator<S>{
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }
        // 覆写Iterator接口的hasNext方法
        public boolean hasNext() {
            // ...暂时省略相关代码
        }
        // 覆写Iterator接口的next方法
        public S next() {
            // ...暂时省略相关代码
        }
        // 覆写Iterator接口的remove方法
        public void remove() {
            // ...暂时省略相关代码
        }

    }

    // 覆写Iterable接口的iterator方法,返回一个迭代器
    public Iterator<S> iterator() {
        // ...暂时省略相关代码
    }

    // ...暂时省略相关代码

}

可以看到,ServiceLoader实现了Iterable接口,覆写其iterator方法能产生一个迭代器;同时ServiceLoader有一个内部类LazyIterator,而LazyIterator又实现了Iterator

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值