SPI机制及应用

一、什么是SPI

SPI ,全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。

1、SPI 示例

在这里插入图片描述

首先,我们需要定义一个接口,SPIService

package com.viewscenes.netsupervisor.spi; 
public interface SPIService { 
    void execute();
}

然后,定义两个实现类,只输入一句话。

package com.viewscenes.netsupervisor.spi;
public class SpiImpl1 implements SPIService{
    public void execute() {
        System.out.println("SpiImpl1.execute()");
    }
}
package com.viewscenes.netsupervisor.spi;
public class SpiImpl2 implements SPIService{
    public void execute() {
        System.out.println("SpiImpl2.execute()");
    }
}

最后,要在ClassPath路径下配置添加一个文件。文件名字是接口的全限定类名,内容是实现类的全限定类名,多个实现类用换行符分隔。 文件路径如下:

SPI配置文件位置 内容就是实现类的全限定类名:

com.viewscenes.netsupervisor.spi.SpiImpl1 com.viewscenes.netsupervisor.spi.SpiImpl

2 2、测试 然后我们就可以通过ServiceLoader.load或者Service.providers方法拿到实现类的实例。其中,Service.providers包位于sun.misc.Service,而ServiceLoader.load包位于java.util.ServiceLoader

public class Test { 
    public static void main(String\[\] args) {
        Iterator<SPIService> providers = Service.providers(SPIService.class); 
        ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
        while(providers.hasNext()) {
            SPIService ser = providers.next();
            ser.execute();
        }
        System.out.println("--------------------------------");
        Iterator<SPIService> iterator = load.iterator();
        while(iterator.hasNext()) {
            SPIService ser = iterator.next();
            ser.execute();
        }
    }
}

两种方式的输出结果是一致的:

SpiImpl1.execute()
SpiImpl2.execute()
--------------------------------
SpiImpl1.execute()
SpiImpl2.execute()

已上参考 https://www.jianshu.com/p/3a3edbcd8f24

二、应用

1、springmvc零配置

servlet 2.5的项目中,我们如果想要添加一个servlet,就需要在web.xml文件中进行配置。
在新的servlet 3.0标准中,我们可以通过@WebServlet注解,实现零配置添加新的servlet。
但是我们在spring webmvc的DispatcherServlet这个最重要的servlet中却没有看到@WebServlet这个注解,那么,DispatcherServlet又是如果注册到servlet容器中的呢?其实servlet还提供了第三种注册Servlet的方式,也就是编码的方式,而spring webmvc是在什么地方编码注册servlet的,就涉及到上面提到SPI了。
在servlet规范中,定义了一个SPI javax.servlet.ServletContainerInitializer,实现支持servlet的web容器在启动的时候,要扫描classpath路径下的META-INFO/service,看有没有一个命名为javax.servlet.ServletContainerInitializer的文件,该文件的内容是javax.servlet.ServletContainerInitializer的实现类org.springframework.web.SpringServletContainerInitializer,接着,web容器需要解析实现类的@HandlesTypes注解,搜索项目中,该注解中配置的值(一个接口,WebApplicationInitializer.class)对应的所有实现类,然后将所有找到的实现类的集合作为参数,在调用实现类(org.springframework.web.SpringServletContainerInitializer)的onStartup方法的时候传入。具体可以参考我的这篇文章 SpringMVC的“main”函数

2、 spring boot的运作原理

spring boot 并未使用 Java SPI,而是重新实现了一套 SPI 机制。关于spring boot的运作原理,我们还是回归到@springBootApplication注解上来,这个注解是一个组合注解,它的核心功能是由@EnableAutoConfigruation注解提供的。 下面我们来看下@EnableAutoConfiguration注解的源码:

这里的关键功能是@Import注解导入的配置功能,EnableAutoConfigurationImportSelector使用SpringFactoriesLoader。loadFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包,而我们的spring-boot-autoconfigure-x.x.x.x.jar里面就有一个spring.factories文件。 spring boot自动配置的问题可见我以前的文章 Spring Boot自动配置(原理篇)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值