JAVA使用ServiceLoader加载服务

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/jianggujin/article/details/81030983

ServiceLoaderSPI的是一种实现,所谓SPI,即Service Provider Interface,用于一些服务提供给第三方实现或者扩展,可以增强框架的扩展或者替换一些组件。
其实关于ServiceLoader,我们平时虽然很少用到,但是却在背后为我们做了很多事情,最常见的就是JDBC的操作了,相信大家对DriverManager类并不陌生,我们可以通过该类加载驱动并获得数据库连接,在这个类中其实就用到了ServiceLoader

private static void loadInitialDrivers() {
    String drivers;
    try {
        drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return System.getProperty("jdbc.drivers");
            }
        });
    } catch (Exception ex) {
        drivers = null;
    }
    // If the driver is packaged as a Service Provider, load it.
    // Get all the drivers through the classloader
    // exposed as a java.sql.Driver.class service.
    // ServiceLoader.load() replaces the sun.misc.Providers()

    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {

            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
            Iterator<Driver> driversIterator = loadedDrivers.iterator();

            /* Load these drivers, so that they can be instantiated.
             * It may be the case that the driver class may not be there
             * i.e. there may be a packaged driver with the service class
             * as implementation of java.sql.Driver but the actual class
             * may be missing. In that case a java.util.ServiceConfigurationError
             * will be thrown at runtime by the VM trying to locate
             * and load the service.
             *
             * Adding a try catch block to catch those runtime errors
             * if driver not available in classpath but it's
             * packaged as service and that service is there in classpath.
             */
            try{
                while(driversIterator.hasNext()) {
                    driversIterator.next();
                }
            } catch(Throwable t) {
            // Do nothing
            }
            return null;
        }
    });

    println("DriverManager.initialize: jdbc.drivers = " + drivers);

    if (drivers == null || drivers.equals("")) {
        return;
    }
    String[] driversList = drivers.split(":");
    println("number of Drivers:" + driversList.length);
    for (String aDriver : driversList) {
    try {
        println("DriverManager.Initialize: loading " + aDriver);
        Class.forName(aDriver, true,
                ClassLoader.getSystemClassLoader());
        } catch (Exception ex) {
            println("DriverManager.Initialize: load failed: " + ex);
        }
    }
}

接下来我们就还看看如何使用ServiceLoader,假设我们需要一个日志的服务,那么首先我们需要定义一个服务的接口

package com.jinggujin.service;

public interface LogService {
   void log(String msg);
}

针对这个服务我们再来提供一个实现

package com.jinggujin.service;

public class DefaultLogService implements LogService {

   @Override
   public void log(String msg) {
      System.out.println(msg);
   }
}

好了下面我们需要提供我们的服务,我们需要在META-INF中添加services文件夹,然后在该文件夹中创建一个文件,文件名为服务接口的全限定类名,那么这里完整的文件路径应为:META-INF/services/com.jinggujin.service.LogService,最后我们需要在该文件中添加服务实现的全限定类名,一行数据一个实现全限定类名,文件内容如下:

com.jinggujin.service.DefaultLogService

准备工作已经完成,我们就来使用ServiceLoader加载我们提供的服务。

package test;

import java.util.ServiceLoader;

import org.junit.Test;

import com.jinggujin.service.LogService;

public class ServiceLoaderTest {
   @Test
   public void test() {
      ServiceLoader<LogService> loader = ServiceLoader.load(LogService.class);

      for (LogService service : loader) {
         System.out.println(service.getClass());
      }
   }
}

运行结果如下:

class com.jinggujin.service.DefaultLogService
阅读更多

扫码向博主提问

蒋固金

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • java
  • oracle
  • js
去开通我的Chat快问

没有更多推荐了,返回首页