`
234390216
  • 浏览: 10218709 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
A5ee55b9-a463-3d09-9c78-0c0cf33198cd
Oracle基础
浏览量:462011
Ad26f909-6440-35a9-b4e9-9aea825bd38e
springMVC介绍
浏览量:1774437
Ce363057-ae4d-3ee1-bb46-e7b51a722a4b
Mybatis简介
浏览量:1397500
Bdeb91ad-cf8a-3fe9-942a-3710073b4000
Spring整合JMS
浏览量:394706
5cbbde67-7cd5-313c-95c2-4185389601e7
Ehcache简介
浏览量:679508
Cc1c0708-ccc2-3d20-ba47-d40e04440682
Cas简介
浏览量:530293
51592fc3-854c-34f4-9eff-cb82d993ab3a
Spring Securi...
浏览量:1180703
23e1c30e-ef8c-3702-aa3c-e83277ffca91
Spring基础知识
浏览量:466018
4af1c81c-eb9d-365f-b759-07685a32156e
Spring Aop介绍
浏览量:151030
2f926891-9e7a-3ce2-a074-3acb2aaf2584
JAXB简介
浏览量:67733
社区版块
存档分类
最新评论

Java SPI机制简介

    博客分类:
  • java
阅读更多

Java SPI机制简介

 

         SPIService Provider Interfaces的简称。根据JavaSPI规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即Service Provider(服务提供者)。然后在使用的时候只要根据SPI的规范去获取对应的服务提供者的服务实现即可。为了便于理解,我们先来看一个使用SPI的示例。

         假设我们有一个日志服务LogService,其只定义了一个info方法用于输出日志信息,我们希望把它作为SPI,然后具体的实现由对应的服务提供者去实现。LogService的定义如下所示。

 

package com.elim.learn.basic.spi.service;

 

public interface LogService {

 

   public void info(String msg);

  

}

 

         然后基于这个服务我们会有自己的实现,示例中笔者用了三个实现,分别是ConsoleLogServiceFileLogServiceDBLogService,其实现都只是简单的打印一下日志类别信息,ConsoleLogService的实现如下所示,其它两个是类似的。

package com.elim.learn.basic.spi.service.impl;

 

import com.elim.learn.basic.spi.service.LogService;

 

public class ConsoleLogService implements LogService {

 

   @Override

   public void info(String msg) {

      System.out.println("----console log ----");

   }

 

}

 

         根据SPI的规范我们的服务实现类必须有一个无参构造方法。我们的SPI服务提供者需要将其在classpath下的META-INF/services目录下以服务接口全路径名命名的文件中写对应的实现类的全路径名称,每一行代表一个实现,如果需要注释信息可以使用“#”进行注释,根据官方的要求,这个文件的编码格式必须是UTF-8。我们示例中的LogService的全路径名是com.elim.learn.basic.spi.service.LogService,所以我们需要在类路径下的META-INF/services目录下创建一个名称为com.elim.learn.basic.spi.service.LogService文件。在本示例中我们一个提供了三个实现,所以该文件的内容如下。

#console

 

 

 

com.elim.learn.basic.spi.service.impl.ConsoleLogService

 

 

 

 

#file

 

 

 

 

com.elim.learn.basic.spi.service.impl.FileLogService

 

 

 

 

 

#db

 

 

 

 

 

 

 

com.elim.learn.basic.spi.service.impl.DBLogService

 

         至此,我们的服务定义和实现配置就完成了,接下来就是使用了。使用的时候核心是ServiceLoader类,我们需要通过这个工具类来加载服务提供者,即对应的服务实现,也需要通过它来获得对应的服务实现。ServiceLoader类的核心入口是其提供的三个可以创建ServiceLoader实例的静态方法,分别是load(Class<?> , ClassLoader)load(Class<?>)loadInstalled(Class<?>),三者的区别就在于使用的ClassLoader不一样。load(Class<?>)方法将使用当前线程持有的ClassLoaderloadInstalled(Class<?>)方法将使用最顶级的ClassLoader。三者的实现分别如下。

    public static <S> ServiceLoader<S> load(Class<S> service,

                                            ClassLoader loader)

    {

        return new ServiceLoader<>(service, loader);

    }

 

    public static <S> ServiceLoader<S> load(Class<S> service) {

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

        return ServiceLoader.load(service, cl);

    }

 

    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {

        ClassLoader cl = ClassLoader.getSystemClassLoader();

        ClassLoader prev = null;

        while (cl != null) {

            prev = cl;

            cl = cl.getParent();

        }

        return ServiceLoader.load(service, prev);

    }

 

         ServiceLoader是实现了java.util.Iterator接口的,而且是基于我们所使用的服务的实现,所以可以通过ServiceLoader的实例来遍历其中的服务实现者,从而调用对应的服务提供者。示例如下。

   @Test

   public void test() {

      ServiceLoader<LogService> serviceLoader = ServiceLoader.load(LogService.class);

      LogService logService = null;

      for (Iterator<LogService> iter = serviceLoader.iterator(); iter.hasNext(); ) {

        logService = iter.next();

        logService.info("Hello SPI");

      }

      //由于ServiceLoader是实现了java.util.Iterator接口的,也可以使用增强的for循环

      for (LogService service : serviceLoader ) {

        service.info("Hello SPI");

      }

   }

 

         调用结果如下:


         在上述示例中我们的基于SPI规范的服务定义和服务实现都是在一个工程里面的,且都是可以看到源码的,但在实际应用中我们的服务提供者往往是以jar包的形式来提供对应的服务实现的。ServiceLoader不是一实例化以后立马就去读配置文件中的服务实现者,并且进行对应的实例化工作的,而是会等到需要通过其Iterator实现获取对应的服务提供者时才会加载对应的配置文件进行解析,具体来说是在调用IteratorhasNext方法时会去加载配置文件进行解析,在调用next方法时会将对应的服务提供者进行实例化并进行缓存。所有的配置文件只加载一次,服务提供者也只实例化一次,如需要重新加载配置文件可调用ServiceLoaderreload方法。有兴趣的朋友可以参考一下ServiceLoader的完整源码实现。

 

 

 

 

  • 大小: 3 KB
1
1
分享到:
评论

相关推荐

    Java SPI 机制(SPI实战+ServiceLoader源码分析+SPI 应用场景+破坏双亲委派)

    Java SPI 机制详解 Java SPI 机制,全称 Service Provider Interface,是 Java 内置的服务发现机制。SPI 机制的主要思想是解耦,通过提供一个标准接口,允许第三方提供实现类,而无需在程序中硬编码。SPI 机制广泛...

    Java类加载及SPI机制.pdf

    而SPI机制则提供了一种通用的方式来扩展Java平台功能,使得Java开发者可以在不修改源码的情况下增强平台或第三方库的功能。在实际开发过程中,深入理解和正确使用这两个机制,对于提升软件的灵活性、可维护性以及可...

    Java SPI机制详解.md

    Java SPI机制详解.md

    java SPI机制实现服务接口和服务实现分离源码Demo

    SPI机制的核心是`java.util.ServiceLoader`类,它允许我们按照约定在`META-INF/services`目录下创建配置文件,来指定哪些类实现了特定的服务接口。 服务接口定义:在SPI机制中,首先我们需要定义一个服务接口,这个...

    Java 基础(8-8)-Java常用机制 - SPI机制详解.pdf

    Java SPI 机制详解 Java SPI(Service Provider Interface)机制是一种服务提供发现机制,能够实现框架的扩展和替换组件,主要被框架的开发人员使用。SPI 机制的核心思想是将装配的控制权移到程序之外,在模块化...

    java spi实现工程

    Java SPI(Service Provider Interface)是Java平台提供的一种服务发现机制,允许JVM在运行时动态加载服务提供商。这个机制使得开发者可以扩展应用的功能,而无需修改原有代码。SPI的核心概念在于,服务接口由主程序...

    java SPI的jar包

    这个资源是我的博客《java SPI机制学习笔记》中的提供服务的jar包

    java spi 可运行 demo

    Java SPI(Service Provider Interface)是Java标准库提供的一种服务发现机制,它允许程序在运行时动态地查找并...`spitest`项目可能是一个用于演示如何使用和配置SPI的示例,可以帮助开发者更好地理解和应用SPI机制。

    Java SPI机制原理及代码实例

    总结,Java SPI机制为开发者提供了一种灵活的服务发现和加载方式,使得软件系统能够更好地适应变化,降低耦合度,增强系统的可扩展性和可维护性。在实际项目中,合理利用SPI可以提高软件组件的可插拔性,方便集成和...

    Java SPI Demo

    Java SPI(Service Provider Interface)是Java平台提供的一种服务发现机制,允许JVM在运行时动态加载和使用服务提供商。这个机制使得开发者可以扩展应用程序的功能,而不需要修改应用程序的代码。在Java SPI中,...

    Java SPI的简单小实例

    Java SPI机制的应用非常广泛,例如JDBC中的数据库连接驱动接口、Java中的日志记录接口等。这些接口都可以通过SPI机制来加载和实例化服务提供者,从而提供一个灵活的服务加载机制。 在实际应用中,Java SPI机制可以...

    Java的SPI机制实例详解

    Java SPI机制实例详解 Java的SPI机制实例详解是Java提供的一种服务提供商接口机制,英文全名为Service Provider Interface。SPI机制实例详解主要是面向厂商或者插件的,普通开发人员可能不熟悉。Java的SPI机制实例...

    Java类加载及SPI机制.zip

    而SPI机制是Java平台提供的一种灵活的服务发现和加载方式,它促进了模块化开发和插件化的实现,增强了软件的可扩展性。这两个知识点对于Java开发者来说是必不可少的,深入掌握能提高开发效率和代码质量。

    java spi-demo示例

    SPI机制使得开发者可以扩展程序的功能,而无需修改原代码,极大地提高了软件的可扩展性和模块化。 在Java SPI中,服务接口通常定义在`META-INF/services`目录下的一个特定配置文件中,文件名为`接口全限定名`。例如...

    java spi 学习记录

    SPI机制使得开发者可以扩展程序的功能,而无需修改原代码,极大地提高了软件的可扩展性和模块化。 标题“Java SPI 学习记录”表明我们将探讨这个重要的Java特性,并分享学习过程中的一些理解和实践。这篇博客可能...

    java的spi测试

    Java的Service Provider Interface (SPI) 是一种用于在运行时动态发现和加载服务提供者实现的机制。这个功能在Java标准库中被广泛使用,允许开发者扩展JVM的功能,而无需修改核心API。在这个"java的spi测试"中,我们...

    20180620-Dubbo常用配置文件分析-笔记.docx

    - **Java SPI机制简介**: - **定义**:SPI 是 JDK 内置的一种服务提供发现机制。 - **工作原理**:通过在`META-INF/services`目录下放置接口名称的文本文件,列出所有实现类,以此来动态加载和选择服务实现。 - *...

    深入学习Java中的SPI机制

    "深入学习Java中的SPI机制" Java中的SPI(Service Provider Interface)机制是一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用。SPI机制的主要思想是将装配的控制权移到程序...

    java-spi学习例子

    Java SPI(Service Provider Interface)是Java平台提供的一种服务发现机制,允许JVM在运行时动态加载服务实现。这个机制使得开发者可以扩展已存在的应用程序或库,而无需修改原代码。SPI的核心理念是将服务接口与其...

    一款基于hdfs的ftp服务器,通过java的spi机制内置支持多hadoop版本,自带依赖,无需编译即可使用。.zip

    “通过java的spi机制内置支持多hadoop版本”这部分涉及到Java的Service Provider Interface (SPI)机制。SPI是Java提供的一种服务发现框架,允许第三方开发者扩展JVM内置的服务。在这个FTP服务器中,SPI被用来识别和...

Global site tag (gtag.js) - Google Analytics