各种spi机制实现与使用

SPI机制认识

1.java SPI机制

java SPI机制(service provider interface) jdk内置的服务提供发现机制,可以启用框架扩展或替换组件,主要思想是将装配的控制权移到程序之外

通俗的讲就是:为某个接口自动找到实现类并初始化。

使用:

  1. 定义接口
  2. 编写实现类实现接口逻辑
  3. 在类路径下添加目录META-INF/services,并在其下添加以接口权限定类名为名字的文件,内容是实现类的全限定类型名
  4. 使用ServiceLoader.load(接口)
    ServiceLoader contents = ServiceLoader.load(Content.class);
    Iterator iterator = contents.iterator();
    while (iterator.hasNext()) {
    // 调用next()时会使用Class.forName()加载类
    Content content = iterator.next();
    String searchContent = content.searchContent();
    System.out.println("searchContent = " + searchContent);
    }
    缺点:一次性加载所有的实现类,不能实现按需加载

2.spring的 SPI机制

spring会加载所有jar包下的META-INF/spring.factories文件下的所有自动配置类(xxAutoConfiguration),根据引入的starter,会对相应的类进行实例化,在实例化的过程中又会读取xxProperties类中的属性值,此属性值是在application.yml中进行配置的

使用

  1. 定义接口
  2. 编写实现类实现接口逻辑
  3. 在类路径下添加目录META-INF/spring.factories文件,文件内容key=val01,val02。key是接口权限定类名,val是实现类的全限定类型名
  4. 使用SpringFactoriesLoader.loadFactories(接口.class, 类加载器)
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    List factories = SpringFactoriesLoader.loadFactories(Content.class, contextClassLoader);

源码

public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
    Assert.notNull(factoryType, "'factoryType' must not be null");
    ClassLoader classLoaderToUse = classLoader;
    if (classLoaderToUse == null) {
        classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }
    // 读取配置内容
    List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
    if (logger.isTraceEnabled()) {
        logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
    }
    List<T> result = new ArrayList<>(factoryImplementationNames.size());
    for (String factoryImplementationName : factoryImplementationNames) {
        // Class.forName()实例化
        result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
    }
    AnnotationAwareOrderComparator.sort(result);
    return result;
}

参考:深入剖析Spring Boot 的SPI机制

3.dubbo的spi机制

以apache不是alibaba的dubbo实现。使用过滤器为案例

  • 使用一个类实现org.apache.dubbo.rpc.Filter中invoke方法,类上并标注@Activate注解
    @Activate注解有group属性,order属性。
    group属性表示当前spi扩展在什么时候起作用。CommonConstants.PROVIDER表示:作为服务器(生产者)、CommonConstants.CONSUMER表示客户端(消费者)
    order表示被执行的顺序,数字越小优先级越高
    代码如下
      import org.apache.dubbo.common.constants.CommonConstants;
      import org.apache.dubbo.common.extension.Activate;
      import org.apache.dubbo.rpc.*;
      @Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER})
      public class LogRecordSPI implements Filter {
      
          @Override
          public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
              try {
                  return invoker.invoke(invocation);
              } catch (RpcException e) {
                  System.out.println("RpcException");
                  throw new RuntimeException(e);
              } finally {
                  System.out.println("finally");
              }
          }
      }
  • 项目resources目录中创建目录META-INF/dubbo,并创建一个以org.apache.dubbo.rpc.Filter,内容是spi服务id=xxx.xx.xxx.LogRecordSPI,如下
    logRecordSP=com.abucloud.spi.LogRecordSPI
    参考:调用拦截扩展
posted @ 2024-08-15 22:20  永无八哥  阅读(15)  评论(0编辑  收藏  举报