美文网首页
ServiceLoader 的学习

ServiceLoader 的学习

作者: 以梦为马驾驾驾 | 来源:发表于2019-09-26 08:14 被阅读0次

在阅读jaeger-client的源码的时候,看到了ServiceLoader的东西,个人感觉有点像已知多少种子类的策略模式。

他人的解释:ServiceLoader是SPI的是一种实现,所谓SPI,即Service Provider Interface,用于一些服务提供给第三方实现或者扩展,可以增强框架的扩展或者替换一些组件。

我理解的简单做法:通过在jar包的META-INF/services/下,添加文件,文件名为接口的全限定名,内容为希望获得的实现了此接口的类的全限定名。

jaeger-client项目中:
jaeger-thrift模块中,有文件META-INF/services/io.jaegertracing.spi.SenderFactory,此文件内容如下:

io.jaegertracing.thrift.internal.senders.ThriftSenderFactory
io.jaegertracing.thrift.internal.senders.FullLogSenderFactory
io.jaegertracing.internal.senders.NoopSenderFactory

在类io.jaegertracing.internal.senders.SenderResolver中,

    ServiceLoader<SenderFactory> senderFactoryServiceLoader = ServiceLoader.load(SenderFactory.class,
        SenderFactory.class.getClassLoader());
    Iterator<SenderFactory> senderFactoryIterator = senderFactoryServiceLoader.iterator();

    boolean hasMultipleFactories = false;
    while (senderFactoryIterator.hasNext()) {
      SenderFactory senderFactory = senderFactoryIterator.next();

      if (senderFactoryIterator.hasNext()) {
        log.debug("There are multiple factories available via the service loader.");
        hasMultipleFactories = true;
      }

      if (hasMultipleFactories) {
        // we compare the factory name with JAEGER_SENDER_FACTORY, as a way to know which
        // factory the user wants:
        String requestedFactory = System.getProperty(Configuration.JAEGER_SENDER_FACTORY);
        if (senderFactory.getType().equals(requestedFactory)) {
          log.debug(
              String.format("Found the requested (%s) sender factory: %s",
                  requestedFactory,
                  senderFactory)
          );

          sender = getSenderFromFactory(senderFactory, senderConfiguration);
        }
      } else {
        sender = getSenderFromFactory(senderFactory, senderConfiguration);
      }
    }

ServiceLoader的主要方法

    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }
// 若loader参数为null,则使用ClassLoader.getSystemClassLoader(),是AppClassLoader
    public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }
    public Iterator<S> iterator() {
        return new Iterator<S>() {

            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();

            public boolean hasNext() {
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

iterator的next会返回一个实例对象,所以被返回的对象的类要有无参构造方法。

示例:
serviceLoader/
├── ClientToTryCL.java
├── IHelloImpl.java
└── IHello.java
IHelloIHelloImpl

public interface IHello {

   String sayHello(String name);
}


public class IHelloImpl  implements IHello {
  public IHelloImpl() {}
  public String sayHello(String name)  {
//    System.out.println(name + " says hello");
    return name + " says hello";
  }
}

ClientToTryCL

public class ClientToTryCL {


  public static void main(String[] args){
    ServiceLoader<IHello> serviceLoader = ServiceLoader.load(IHello.class);

    Iterator<IHello> iterator = serviceLoader.iterator();

    while(iterator.hasNext()){
      IHello ihello = iterator.next();
      System.out.println(ihello.sayHello(ihello.getClass().getName()));
    }
  }

}

备注:
在不同的jar中,有重复的文件是可以的,我在jaeger-thrifrjaeger-core两个模块中都定义了文件,会依次找下去。
这样用maven打jar包

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.xuan.serviceLoader.ClientToTryCL</mainClass>
                        </manifest>
                    </archive>
                </configuration>

            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

ClassLoader详解

相关文章

网友评论

      本文标题:ServiceLoader 的学习

      本文链接:https://www.haomeiwen.com/subject/lqxvyctx.html