不懂Java SPI机制,怎么进大厂

{

return new ServiceLoader<>(service, loader);

}

public static ServiceLoader load(Class service) {

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

private ServiceLoader(Class 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.load()进行加载。先获取当前线程绑定的 ClassLoader,如果当前线程绑定的 ClassLoadernull,则使用 SystemClassLoader进行代替,而后清除一下provider缓存,最后创建一个 LazyIteratorLazyIterator的部分源码如下:

private class LazyIterator implements Iterator

{

Class service;

ClassLoader loader;

Enumeration configs = null;

Iterator pending = null;

String nextName = null;

public boolean hasNext() {

if (acc == null) {

return hasNextService();

} else {

PrivilegedAction action = new PrivilegedAction() {

public Boolean run() { return hasNextService(); }

};

return AccessController.doPrivileged(action, acc);

}

}

private boolean hasNextService() {

if (nextName != null) {

return true;

}

if (configs == null) {

try {

//key:获取完全限定名

String fullName = PREFIX + service.getName();

if (loader == null)

configs = ClassLoader.getSystemResources(fullName);

else

configs = loader.getResources(fullName);

} catch (IOException x) {

fail(service, “Error locating configuration files”, x);

}

}

while ((pending == null) || !pending.hasNext()) {

if (!configs.hasMoreElements()) {

return false;

}

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

}

nextName = pending.next();

return true;

}

}

key:通过预定好的目录地址以及类名来指定类的具体地址,类加载器根据这个地址来加载具体的实现类。

大致的SPI加载过程如下所示:

Seata如何使用SPI

===============================================================================

Seata是一个分布式事务的框架,具体的使用这里不再赘述,有时间可以出专门写它的文章。本节主要关注Seata是如何利用SPI的方式进行框架能力扩展的。

Seata框架中使用 EnhancedServiceLoader 实现服务载入,通过名称我们可以知道他是一种增强型的ServiceLoader。那么相对于JDK自身的ServiceLoader,他到底强在哪里呢?

由下图可知, EnhancedServiceLoader 不仅支持Java原生的服务发现目录,同样支持自己自定义的META-INF/seata/目录。

另外在具体接口实现类上都有@LoadLevel的注解,如果其中有多个配置中心实现类都被加载,那么可以根据对应注解上的属性order进行排序。将实际优先级最大的类进行加载。

我们都知道注册中心是微服务体系中的必不可少的基础组件,它记录了服务提供者的地址信息。那么在Seata中,Seata的客户端如事务管理器TM、资源管理器RM需要与事务协调者TC进行通信,那么就需要通过注册中心来获取服务端的地址信息。Seata注册中心支持多个第三方注册中心,如ConsulApolloEtcd3等。我们来看下Seata是怎么使用SPI机制来实现对于多个注册中心扩展支持的。

首先定义一个ConfigurationProvider的接口,你看是不是嗅到了熟悉的味道,只要使用SPI那么就需要首先把规矩给小弟们定好。

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

MySQL全家桶笔记

还有更多面试复习笔记分享如下

Java架构专题面试复习

需要首先把规矩给小弟们定好。

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

[外链图片转存中…(img-N65CTZ5r-1714551496940)]

还有更多面试复习笔记分享如下

[外链图片转存中…(img-EfTh6drj-1714551496940)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 27
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值