JAVA-SPI机制

前言

本文是做Dubbo的SPI机制的铺垫文章,那么本文我们就来看看JAVA的SPI是个啥!SPI全称为 (Service Provider Interface),通常在一些第三方框架上有的!本文先使用数据库驱动来讲解一下!市面上有许许多多的数据库,如MySQL、SQLServer、Oracle等等,这些在JAVA中都能对接,是应为有Driver接口在顶层抽象控制!
在这里插入图片描述
Driver提供一套接口规范,那么各第三方数据库驱动依赖需要实现Driver接口,然后各个数据库驱动依赖包中配置实现类全限定名,如下!
在这里插入图片描述
那么这个文件需要放到META-INF.services目录下面,文件名就是Driver接口的全限定名!当程序需要Driver的实现类的时候就可以通过META-INF.services下找到java.sql.Driver,然后通过java.sql.Driver文件中的实现类路径获取实现类!

说白了顶层通过面向Driver接口编程,但是并不知道具体使用那种类型的数据库,那么我们数据库启动包就可以使用JAVA的SPI机制告诉Driver使用那个实现类!用户导入MySQL驱动包,那么就使用com.mysql.cj.jdbc.Driver作为实现类,如果是SQLServer那么就使用SQLServer的!就是这么个意思!

代码编写

场景铺垫
登录现在方式挺多的,我们现在有微信登录、QQ登录、手机短信登录,那么我们在顶层创建一个LoginService接口,LoginService接口中有一个login方法,然后有对应的微信、QQ、手机短信实现类,继承LoginService,实现login方法!

代码目录
在这里插入图片描述
LoginService

public interface LoginService {

    public String login();

}

QqLoginServiceImpl

public class QqLoginServiceImpl implements LoginService {
    @Override
    public String login() {
        return "QQ登录";
    }
}

SmsLoginServiceImpl

public class SmsLoginServiceImpl implements LoginService {
    @Override
    public String login() {
        return "sms登录";
    }
}

WxLoginServiceImpl

public class WxLoginServiceImpl implements LoginService {
    @Override
    public String login() {
        return "WX登录";
    }
}

调用测试


public class JavaSpiApplication {

    public static void main(String[] args) {
        ServiceLoader<LoginService> loginServices = ServiceLoader.load(LoginService.class);
        for (LoginService lo : loginServices) {
            System.out.println(lo.login());
        }
    }
}

METE-INF下创建service目录,添加com.javaspi.service.LoginService文件
在这里插入图片描述

执行结果
在这里插入图片描述

源码分析

流程梳理
通过接口,得到接口信息,然后到META-INF/service下匹配对应的文件,然后得到文件中的实现类全限定名通过反射创建实现类!并存储到迭代器中!

修改代码
替换原有的for为where迭代!让代码更加直观!

public static void main(String[] args) {
        ServiceLoader<LoginService> loginServices = ServiceLoader.load(LoginService.class);
        Iterator<LoginService> iterator= loginServices.iterator();
        while (iterator.hasNext()){
            LoginService next = iterator.next();
            System.out.println(next.login());
        }
    }

ServiceLoader.load(LoginService.class)

ServiceLoader<LoginService> loginServices = ServiceLoader.load(LoginService.class);

这行代码执行就是通过LoginService的信息去构建一个ServiceLoader的,连调方法如下
在这里插入图片描述
先找当前线程绑定的 ClassLoader
在这里插入图片描述
构建ServiceLoader

在这里插入图片描述
赋值service、loader、acc

在这里插入图片描述

lookupIterator = new LazyIterator(service, loader);

实例化一个迭代器!并且将需要加载的接口和类加载器通过构造方法初始化给LazyIterator!在这里插入图片描述
注意LazyIterator是ServiceLoader的内部类!

Iterator iterator= loginServices.iterator();
loginServices.iterator()为什么能点出来呢!因为ServiceLoader中有一个获取迭代器的方法!
在这里插入图片描述
但是这里创建出来的迭代器中的hasNext、next方法变相的都调用着ServiceLoader中内部类LazyIterator中的hasNext和next方法。那么这里就是返回一个迭代器对象。

iterator.hasNext()
这个hashNext会调用lookupIterator.hasNext();
在这里插入图片描述
进入hasNextService()方法
在这里插入图片描述
拼接接口全路径为META-INF/services/com.javaspi.service.LoginService
在这里插入图片描述

pending = parse(service, configs.nextElement());

parse主要就是解析META-INF/services/com.javaspi.service.LoginService文件中的内容,并且返回Iterator
在这里插入图片描述

iterator.next();
iterator.next();方法调用的是lookupIterator.next();方法!
在这里插入图片描述
这里就是通过反射并实例化实现类,并且将实现类返回!

结束语
那么到这里JAVA的SPI机制就分析完成了,后续有时间会在分析Dubbo的SPI机制!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员劝退师-TAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值