2023-2更文21-ServiceLoader相关内容

77 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

ServiceLoader相关内容

前文

本文主要内容是关于java的一个类加载器ServiceLoader的相关内容的总结。

ServiceLoader是什么

类似于classLoader负责在程序初始化阶段的类的加载,serviceLoader也是一个简单的服务提供类加载器,主要作用是将类从文件中加载到程序中,类生命周期的第一阶段。与classLoader有所不同,classLoader可以加载所有类型的类,而serviceLoader实际上主要是用来加载某种类型的类或其子类,也就是加载某个类的子类或某个接口的实现类,这些类一般具有同样的特征或逻辑意义。

ServiceLoader的应用

提到serviceLoader,其实在数据库连接的驱动初始化场景中有所应用,也就是java中所提供的DriverManager类中。通过serviceLoader的加载,可以直接将系统中所引入的所有java.util.Driver的驱动类加载到程序当中,用于作为后续的数据库连接驱动。

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
    while(driversIterator.hasNext()) {
        driversIterator.next();
    }
} catch(Throwable t) {
// Do nothing
}
return null;

如上述代码所示,如果系统中引入了若干的数据库驱动类,且未进行手动的加载初始化,serviceLoader会通过接口进行加载,并对加载的结果进行递归处理。而在递归中,实际上则进行类的初始化操作,下面是递归时所具体执行的内容:

private S nextService() {
    if (!hasNextService())
        throw new NoSuchElementException();
    String cn = nextName;
    nextName = null;
    Class<?> c = null;
    try {
        c = Class.forName(cn, false, loader);
    } catch (ClassNotFoundException x) {
        fail(service,
             "Provider " + cn + " not found");
    }
    if (!service.isAssignableFrom(c)) {
        fail(service,
             "Provider " + cn  + " not a subtype");
    }
    try {
        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
}

如上面的代码所以,实际上将数据库连接驱动加载后,会在递归的过程中进行驱动类的初始化相关操作,将驱动类初始化到系统之中。这样当后续进行数据库的连接处理时,将连接信息传递到数据库驱动管理类后,会进行实际所采用的数据库匹配,找到可采用的数据库驱动,进行后续的数据库连接、操作等处理。

对于平时的使用,我们也完全可以利用serviceLoader进行类的加载处理及初始化操作。但是使用时要注意的是,所采用的类型必须要具备无参数构造方法,实际上该类在加载器的加载过程中执行的是无参的默认构造方法。主要的应用场景则是对于一类接口的实例化处理。

总结

本文主要是介绍了serviceLoader相关知识及其应用的相关内容。