java SPI机制与双亲委派机制的不同 纯原创长文-深入理解Java类加载(双亲委派机制及其破坏 JavaSPI和DubboSPI的区别和联系)

 

1、双亲委派机制

1.1 定义

当一个类加载器收到了类加载的请求的时候,他不会直接去加载指定的类,而是把这个请求委托给自己的父加载器去加载。

如果父类为空,交给bootstrap classloader 加载

如果类还是无法被加载到,则触发findclass,抛出classNotFoundException(findclass这个方法当前只有一个语句,就是抛出classNotFoundException),如果想自己实现类加载器的话,可以继承classLoader后重写findclass方法,加载对应的类)

1.2优点

避免类的重复加载
保护程序安全,防止核心API被随意篡改

2、SPI(service provider interface)定义:

  SPI是jdk内置的一种服务提供发现机制。可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.sql.Driver接口,常用的关系型数据有Mysql、Oracle、SQLServer、DB2等,这些不同类型的数据库使用的驱动程序各不相同,那JDK不可能把所有厂商的驱动都实现,只能制定一个标准接口,其他不同厂商可以针对同一接口做出不同的实现,各个数据库厂商根据标准来实现自己的驱动,这就是SPI机制。

 

 

下面看下Mysql的Driver,以com.mysql.cj.jdbc.Driver 为例

 

 

 

 META-INF目录的作用是相当于信息包,用来配置应用程序、扩展程序、类加载器和服务manifest.mf文件,在打包时自动生成。

 

其中manifest.mf里面描述了程序的基本信息、Main-Class的入口、jar依赖路径Class-Path

而META-INFO/services 的作用是实现接口循环实现类的功能, 除了jdbc模块的方案(Driver)之外,还有日志模块的方案(l4j),xml解析模块等。

 

回到正题:

 com.mysql.cj.jdbc.Driver的源码需要往DriverManager进行注册

最终如下图所示,需要往 registeredDrivers 里面进行添加

 

 

而registeredDrivers 变量在 DriverManager 静态初始化的时候会进行调用把真实的类进行加载出来

 

 

例子

创建一个 interface 接口

 

package com.zhianchen.mysqlremark.springboottest.spi;
/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:25
 */

public interface UserService {
     void login();
}

 

 

 

 

实现

package com.zhianchen.mysqlremark.springboottest.spi.Impl;

import com.zhianchen.mysqlremark.springboottest.spi.UserService;

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:26
 */

public class AppUserLoginServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("AppUserLoginServiceImpl");
    }
}
package com.zhianchen.mysqlremark.springboottest.spi.Impl;

import com.zhianchen.mysqlremark.springboottest.spi.UserService;

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 11:26
 */

public class PCUserLoginServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("PCUserLoginServiceImpl");
    }
}

 

然后在resources 创建目录 META-INF.services  (注意:这里是services 而不是service!!!!!)

创建文件 com.zhianchen.mysqlremark.springboottest.spi.UserService  (这里的文件名要对应UserService包

里面的内容

com.zhianchen.mysqlremark.springboottest.spi.Impl.PCUserLoginServiceImpl
com.zhianchen.mysqlremark.springboottest.spi.Impl.AppUserLoginServiceImpl

 

创建一个Test

/*
 *
 *@Description TODO
 *@Author chenzhian
 *@Date 2022/10/21 14:02
 */
public class SpiTest {
    public static void main(String[] args) {
        ServiceLoader<UserService> serviceLoader= ServiceLoader.load(UserService.class);
        for (UserService userService:serviceLoader
             ) {
            userService.login();
        }
    }
}

 

之前的结果是

PCUserLoginServiceImpl
AppUserLoginServiceImpl

 

参考

纯原创长文-深入理解Java类加载(双亲委派机制及其破坏 JavaSPI和DubboSPI的区别和联系)

https://www.cnblogs.com/masaike/p/15490402.html

META-INF 作用

Java SPI详解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章