原来我们每天都在使用 SPI 服务提供者设计模式

1.引言

接口是对行为的抽象,是接口的实现者和调用者之间建立的约定(协议-protocol)。我们可以根据需要为接口提供不同的实现。通过将不同的接口实现注架构师工资入到调用方,就可以实现在不修改调用方代码的情况下改架构变调用方的产品运营行为。

SPI(Service Provider Interface)就是服务提供者mysql面试题接口模式。框架或者系统可以 SPI 模式支持,让使用方可以根据需要为某个行为选择不同的提供方实现版本,从而实现灵活软件库的可定制扩展。比如Java SDK JDBC 定义了数据库操作的标准接口,但是 Java SDK 并没有提供具体的实现,而是由各个数据库厂商来实现。使用方根据自己的需要选择产品介绍对应数据库的JDBC 实现就好了。

2.SPI 模式

原来我们每天都在使用 SPI 服务提供者设计模式

2.1 模式包产品定位含的组件

服务提供者接口模式中有 4 个重要的组件

  • 服务接口 Service Interface
  • 服务接口实现:不同的服务提供方可以提供一个或多个实现;框架或者系统本mysql数据库命令大全身也可以提供默认的实现。
  • 提供者注册 API(Provider Registration API),这是提供者用来注册实现的;
  • 服务访问 API (Service Access API) ,这是调用方用来获取产品批号是生产日期吗服务的实例的接口。

2.2 简单示例

举个例子,假如我们有个软件产品java培训该产品需要实现一个新功能,以支持从其软件技术他内容系统检架构图索信息。 为了能够支持任意可能的内容系统,我们决定使用 SPI 模式来解决这个问题。Java 提供了 SPI 支持,我们的示例架构师和程序员的区别将会基于 Java SPI。

2.2.1 定义服务接口

首先,我们需要定义服软件工程师务接口

package com.examples.spi
public interface Searchable {
    public List<String> searchDoc(String keyword);   
}

2.2.2 提供者实现服务接口

然后,服务提供者实现接口。在我们的内容搜索服务中,我们可以客户提供实现,客户自己如果架构是什么意思有开发能力,可以可以为自己的内容系统提供搜索实现。

我们有mysql基础命令很多客户使用软件工程专业的内容系统就mysql面试题是同一软件工程个电脑上的文件系统,为了这个这类客户,我们提供了支持文件系统的 Searcha产品设计专业ble 实现:

package com.examples.spi.impl.file;
public class FileSearchEngine implements Searchable{
    @Override
    public List<String> searchDoc(String keyword) {
        log.info("在文件系统中搜索包含 {} 的内容", keyword);
        ... //省略具体实现
        return contents;
    }
}

除了使软件用文件内容系统的客户,其他的客户使用数据库内容系统,为此,我们提供了支持数据库系统的 Searchable 实现:

package com.examples.spi.impl.db;
public class DatabaseSearchEngine implements Searchable{
    @Override
    public List<String> searchDoc(String keyword) {
        log.info("在数据库系统中搜索包含 {} 的内容", keyword);
        ... //省略具体实现
        return contents;
    }
}

2.2.3 注册服务提供者软件技术专业的实现

完成实现后,我java怎么读们需要将实现通过注册接口注册到系统中。 Java SPI 提供了注册机制。该机制是通过配置文件:META-INF/services/interface全限定名 来实现服务实现注册。即在使用mysql索引服务的代码工程中创建 META-INF/service软件s/目录,然后新建文件名为接口全限定名的服务实现注册文件:com.exam架构工程师ples.s架构师工资pi.Searchable。如果我们在这个服务实现注册文件中配置com.exa软件工程mples.spi.impl.file.FileSearchEngine,系统将会使用 FileSearchEngine;如果我们在这个服务实现注册文件中配置com.examples.sjava面试题pi.impl.db.DatabaseSearchEngine,那么系统使用的就是 Databas产品生命周期eSearchEngine产品设计专业

2.2.4 通过服务访问接java培训口调mysql数据库用服务

Java SPI 的服务访问接口时 ServiceLoader。ServiceLoader 可以从服务实现注册文件中加载软件库服务实现,并返回服务对象实例。下面我们通过简单的例子来看看如果获取服务实现对象,并调用服务接口。在这个例子中我们采用了支持多个服务实现的方式。所以如果在服务实架构师工资现注册文件配置了多个实现,那么将会可以从多个内容系统搜索内容。

public class SeachableTest {
    public static void main(String[] args) {
        ServiceLoader<Search> s = ServiceLoader.load(Searchable.class);
        Iterator<Search> iterator = s.iterator();
        while (iterator.hasNext()) {
           Search search =  iterator.next();
           search.searchDoc("hello world");
        }
    }
}

假如你是公司基础架构组的,负责提供公司范围内使用的基础框架和基础设施组件,你们组提供的框架和组件都是用 log4j 写日志。但是业务开发组有的用log4j、有的用logback、有的用JUL(Java Uti软件l Ljava语言ogging)。没有使用log4j 的开发组不得不为工程维护两个日志配置文件。

2.3 示例:JDBC

在JDBC4.0之前,我们开发有连接数据库的时候,通常会用Cmysql数据库命令大全lass.forName(软件库“com.mysql.jdbc.Driver”)这句先加载数据库相关的驱动,然后再进行获取连接等的操作。而JDBC4.0之后软件商店不需要用Class.forName(“com.mysql.jdbc.D架构师和程序员的区别river”)来加载驱动,直接获取连接就可以了,现在这种方式就是使用了Java的SPI扩展机制来实现

2.3.1 JDBC 服务接口定义

Javjava环境变量配置a SDK 中定义了接口java.sql产品设计.Djava模拟器river,并且没有具体的实现,具体的实现都是架构工程师由不同数据库厂商来提供的。

2.3.2 实现

mysqjava环境变量配置l 实现

在 mysql 的 jar 包 mysql-connector-java-6.0.6.jar 中,可以找到META-INF/services目录,软件商店下载该目录下会有一个名字为java.sql.Driver的文件,文件内容是 com.mysq软件l.cj.jdbc.Driver,这里面的内容就是针对Java中定义的接口的实现。

posjavaeetgresql 实现

同样在 postgresql 的 jar 包 postgresql-42.0.0.jar中,也可以找到同样的配置文件,文件内容是 org.mysql基础命令postgresql.Driver,这是postgresql对Java的java.产品介绍sql.Driver的实现。

服务访问接口

上面说了,现在使用SPI扩展来加载具体的驱动,我们在Java中写连接数据库的代java编译器码的时候,不需要再使用Class.forName("com.mysql.jdbc.Driver")来加载驱动了,而是直接使用如下代码:

String url = "jdbc:xxxx://xxxx:xxxx/xxxx";
Connection conn = DriverManager.getConnection(url,username,password);
.....

由于JDBC 服务接口涉及内容多,所以 Java SDK 提供了服mysql密码忘记了怎么办务访问接软件工程师口的封装 DriverManagerDriverManager.loadInitialDrivers 方法中调用了ServiceLoader.load

private static void loadInitialDrivers() {
    String drivers;
    ...
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {
            //使用SPI的ServiceLoader来加载接口的实现
            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
            Iterator<Driver> driversIterator = loadedDrivers.iterator(); 
            try{ 
                // 遍历所有的驱动实现,在遍历的时候,首先调用`driversIterator.hasNext()`方法,
                // 搜索classpath下和jar包中所有的`META-INF/services`目录下的`java.sql.Driver`文件,并找到文件中的实现类的名字
                while (driversIterator.hasNext()) { 
                    driversIterator.next(); } 
            } catch(Throwable t) { 
                // Do nothing 
            }
            ...
        }
    });
    println("DriverManager.initialize: jdbc.drivers = " + drivers);
    ...
}

我们现在更多的是使用 Spring 及 ORM(MyBatis),所以我们基本上很少会之间产品策略与 JDBC软件技术专业 打交道了,这里只是作为 SPI 的示例讲解。JDBC 是经java培训典的 SPI 模式的应用架构师工资

2.4 示例:slf4j 日志框架

3 总结

软件商店有很多我们日常使用的组件/框架使用了SPI,比如 slf4j,common-ljavascriptogging,Springboot 的自动装配插件机制等等。当一个服务行为需要由第三方或者使用方根据场景做不同的适配或扩展的时候,可以使产品批号是生产日期吗用 SPI 模式来实mysql安装现灵活的定制扩展。

发表评论

提供最优质的资源集合

立即查看 了解详情