Java最全组件化框架设计之Java SPI机制(三),2024年Java程序员职业规划

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

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

需要这份系统化的资料的朋友,可以点击这里获取

}

3.java.util.ServiceLoader 加载spi实现类.

上一步的核心代码如下,我们接着分析:

//java.util.serviceLoader.java

ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);

Iterator driversIterator = loadedDrivers.iterator();

try{

//查找具体的实现类的全限定名称

while(driversIterator.hasNext()) {

//加载并初始化实现

driversIterator.next();

}

} catch(Throwable t) {

// Do nothing

}

主要是通过ServiceLoader来完成的,我们按照执行顺序来看看ServiceLoader实现:

//初始化一个ServiceLoader,load参数分别是需要加载的接口class对象,当前类加载器

public static ServiceLoader load(Class service) {

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

return ServiceLoader.load(service, cl);

}

public static ServiceLoader load(Class service,

ClassLoader loader)

{

return new ServiceLoader<>(service, loader);

}

遍历所有存在的service实现

public boolean hasNext() {

if (acc == null) {

return hasNextService();

} else {

PrivilegedAction action = new PrivilegedAction() {

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

};

return AccessController.doPrivileged(action, acc);

}

}

//写死的一个目录

private static final String PREFIX = “META-INF/services/”;

private boolean hasNextService() {

if (nextName != null) {

return true;

}

if (configs == null) {

try {

String fullName = PREFIX + service.getName();

//通过相对路径读取classpath中META-INF目录的文件,也就是读取服务提供者的实现类全限定名

if (loader == null)

configs = ClassLoader.getSystemResources(fullName);

else

configs = loader.getResources(fullName);

} catch (IOException x) {

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

}

}

//判断是否读取到实现类全限定名,比如mysql的“com.mysql.jdbc.Driver

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

if (!configs.hasMoreElements()) {

return false;

}

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

}

nextName = pending.next();//nextName保存,后续初始化实现类使用

return true;//查到了 返回true,接着调用next()

}

public S next() {

if (acc == null) {//用来判断serviceLoader对象是否完成初始化

return nextService();

} else {

PrivilegedAction action = new PrivilegedAction() {

public S run() { return nextService(); }

};

return AccessController.doPrivileged(action, acc);

}

}

private S nextService() {

if (!hasNextService())

throw new NoSuchElementException();

String cn = nextName;//上一步找到的服务实现者全限定名

nextName = null;

Class<?> c = null;

try {

//加载字节码返回class对象.但并不去初始化(换句话就是说不去执行这个类中的static块与static变量初始化)

//

c = Class.forName(cn, false, loader);

} catch (ClassNotFoundException x) {

fail(service,

“Provider " + cn + " not found”);

}

if (!service.isAssignableFrom©) {

fail(service,

“Provider " + cn + " not a subtype”);

}

try {

//初始化这个实现类.将会通过static块的方式触发实现类注册到DriverManager(其中组合了一个CopyOnWriteArrayList的registeredDrivers成员变量)中

S p = service.cast(c.newInstance());

providers.put(cn, p);//本地缓存 (全限定名,实现类对象)

return p;

} catch (Throwable x) {

fail(service,

“Provider " + cn + " could not be instantiated”,

x);

}

throw new Error(); // This cannot happen

}

上一步中,Sp = service.cast(c.newInstance()) 将会导致具体实现者的初始化,比如mysqlJDBC,会触发如下代码:

//com.mysql.jdbc.Driver.java

private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList<>();

static {

try {

//并发安全的想一个copyOnWriteList中方

java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

throw new RuntimeException(“Can’t register driver!”);

}

}

4.最终Driver全部注册并初始化完毕,开始执行DriverManager.getConnection(url, “root”, “root”)方法并返回。

使用实例

四个项目:spiInterface、spiA、spiB、spiDemo

spiInterface中定义了一个com.zs.IOperation接口。

spiA、spiB均是这个接口的实现类,服务提供者。

spiDemo作为客户端,引入spiA或者spiB依赖,面向接口编程,通过spi的方式获取具体实现者并执行接口方法。

├─spiA

│ └─src

│ ├─main

│ │ ├─java

│ │ │ └─com

│ │ │ └─zs

│ │ ├─resources

│ │ │ └─META-INF

│ │ │ └─services

│ │ └─webapp

│ │ └─WEB-INF

│ └─test

│ └─java

├─spiB

│ └─src

│ ├─main

│ │ ├─java

│ │ │ └─com

│ │ │ └─zs

│ │ ├─resources

│ │ │ └─META-INF

│ │ │ └─services

│ │ └─webapp

│ │ └─WEB-INF

│ └─test

│ └─java

├─spiDemo

│ └─src

│ ├─main

│ │ ├─java

│ │ │ └─com

│ │ │ └─zs

│ │ ├─resources

│ │ └─webapp

│ │ └─WEB-INF

│ └─test

│ └─java

└─spiInterface

└─src

├─main

│ ├─java

│ │ └─com

│ │ └─zs

│ ├─resources

│ └─webapp

│ └─WEB-INF

└─test

└─java

└─spiInterface

spiDemo

package com.zs;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.Iterator;

import java.util.ServiceLoader;

public class Launcher {

public static void main(String[] args) throws Exception {

// jdbcTest();

showSpiPlugins();

}

private static void jdbcTest() throws SQLException {

String url = “jdbc:mysql://localhost:3306/test”;

Connection conn = DriverManager.getConnection(url, “root”, “root”);

Statement statement = conn.createStatement();

ResultSet set = statement.executeQuery(“select * from test.user”);

while (set.next()) {

System.out.println(set.getLong(“id”));

System.out.println(set.getString(“userName”));

System.out.println(set.getInt(“age”));

}

}

private static void showSpiPlugins() {

ServiceLoader operations = ServiceLoader.load(IOperation.class);

Iterator operationIterator = operations.iterator();

while (operationIterator.hasNext()) {

IOperation operation = operationIterator.next();

System.out.println(operation.operation(6, 3));

}

}

}

SPI示例 完整代码。

原文链接https://blog.csdn.net/lemon89/article/details/79189475

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

image.png

  • RabbitMQ实战指南

image.png

  • 手写RocketMQ笔记

image.png

  • 手写“Kafka笔记”

image

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

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

需要这份系统化的资料的朋友,可以点击这里获取

15354894312)]

  • 手写RocketMQ笔记

[外链图片转存中…(img-sNwjhVtu-1715354894312)]

  • 手写“Kafka笔记”

[外链图片转存中…(img-SLVZO7Lw-1715354894312)]

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

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

需要这份系统化的资料的朋友,可以点击这里获取

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值