最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java SPI的簡單小實(shí)例

 更新時間:2020年07月13日 09:59:54   作者:不想下火車的人  
這篇文章主要介紹了Java SPI的簡單小實(shí)例,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

  JDK有個ServiceLoader類,在java.util包里,支持按約定目錄/META-INF/services去找到接口全路徑命名的文件,讀取文件內(nèi)容得到接口實(shí)現(xiàn)類的全路徑,加載并實(shí)例化。如果我們在自己的代碼中定義一個接口,別人按接口實(shí)現(xiàn)并打包好了,那么我們只需要引入jar包,通過ServiceLoader就能夠把別人的實(shí)現(xiàn)用起來。舉個例子,JDK中的JDBC提供一個數(shù)據(jù)庫連接驅(qū)動接口,不同的廠商可以有不同的實(shí)現(xiàn),如果它們給的jar包里按規(guī)定提供了配置和實(shí)現(xiàn)類,那么我們就可以執(zhí)行不同的數(shù)據(jù)庫連接操作,比如MySql的jar包里就會有自己的配置:

  這里文件名就是接口:

   文件內(nèi)容是實(shí)現(xiàn)類:

  我們自己實(shí)現(xiàn)一個簡單例子,不需要打jar包,把目錄放到spring boot的resources下即可,這里就是classpath,跟你放jar包里效果一樣。

  1、定義一個接口:

package com.wlf.service;

public interface ITest {
  void saySomething();
}

  2、定義兩個實(shí)現(xiàn):

package com.wlf.service.impl;

import com.wlf.service.ITest;

public class ITestImpl1 implements ITest {
  @Override
  public void saySomething() {
    System.out.println("Hi, mia.");
  }
}
package com.wlf.service.impl;

import com.wlf.service.ITest;

public class ITestImpl2 implements ITest {
  @Override
  public void saySomething() {
    System.out.println("Hello, world.");
  }
}

  3、按預(yù)定新增/META-INF/services/com.wlf.service.ITest文件:

com.wlf.service.impl.ITestImpl1
com.wlf.service.impl.ITestImpl2

  4、定義一個執(zhí)行類,通過ServiceLoader加載并實(shí)例化,調(diào)用實(shí)現(xiàn)類方法,跑一下:

package com.wlf.service;

import java.util.Iterator;
import java.util.ServiceLoader;

public class TestServiceLoader {
  public static void main(String[] args) {
    ServiceLoader<ITest> serviceLoader = ServiceLoader.load(ITest.class);
    Iterator<ITest> iTests = serviceLoader.iterator();
    while (iTests.hasNext()) {
      ITest iTest = iTests.next();
      System.out.printf("loading %s\n", iTest.getClass().getName());
      iTest.saySomething();
    }
  }
}

  打印結(jié)果:

  ServiceLoader源碼比較簡單,可以看下上面我們使用到的標(biāo)黃了的方法:

/**
   * Lazily loads the available providers of this loader's service.
   *
   * <p> The iterator returned by this method first yields all of the
   * elements of the provider cache, in instantiation order. It then lazily
   * loads and instantiates any remaining providers, adding each one to the
   * cache in turn.
   *
   * <p> To achieve laziness the actual work of parsing the available
   * provider-configuration files and instantiating providers must be done by
   * the iterator itself. Its {@link java.util.Iterator#hasNext hasNext} and
   * {@link java.util.Iterator#next next} methods can therefore throw a
   * {@link ServiceConfigurationError} if a provider-configuration file
   * violates the specified format, or if it names a provider class that
   * cannot be found and instantiated, or if the result of instantiating the
   * class is not assignable to the service type, or if any other kind of
   * exception or error is thrown as the next provider is located and
   * instantiated. To write robust code it is only necessary to catch {@link
   * ServiceConfigurationError} when using a service iterator.
   *
   * <p> If such an error is thrown then subsequent invocations of the
   * iterator will make a best effort to locate and instantiate the next
   * available provider, but in general such recovery cannot be guaranteed.
   *
   * <blockquote style="font-size: smaller; line-height: 1.2"><span
   * style="padding-right: 1em; font-weight: bold">Design Note</span>
   * Throwing an error in these cases may seem extreme. The rationale for
   * this behavior is that a malformed provider-configuration file, like a
   * malformed class file, indicates a serious problem with the way the Java
   * virtual machine is configured or is being used. As such it is
   * preferable to throw an error rather than try to recover or, even worse,
   * fail silently.</blockquote>
   *
   * <p> The iterator returned by this method does not support removal.
   * Invoking its {@link java.util.Iterator#remove() remove} method will
   * cause an {@link UnsupportedOperationException} to be thrown.
   *
   * @implNote When adding providers to the cache, the {@link #iterator
   * Iterator} processes resources in the order that the {@link
   * java.lang.ClassLoader#getResources(java.lang.String)
   * ClassLoader.getResources(String)} method finds the service configuration
   * files.
   *
   * @return An iterator that lazily loads providers for this loader's
   *     service
   */
  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();
      }

    };
  }

  我們用到的迭代器其實(shí)是一個Map:

  // Cached providers, in instantiation order
  private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

  它用來緩存加載的實(shí)現(xiàn)類,真正執(zhí)行的是lookupIterator:

  // The current lazy-lookup iterator
  private LazyIterator lookupIterator;

  我們看下它的hasNext和next方法:

public boolean hasNext() {
      if (acc == null) {
        return hasNextService();
      } else {
        PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
          public Boolean run() { return hasNextService(); }
        };
        return AccessController.doPrivileged(action, acc);
      }
    }

    public S next() {
      if (acc == null) {
        return nextService();
      } else {
        PrivilegedAction<S> action = new PrivilegedAction<S>() {
          public S run() { return nextService(); }
        };
        return AccessController.doPrivileged(action, acc);
      }
    }
private boolean hasNextService() {
      if (nextName != null) {
        return true;
      }
      if (configs == null) {
        try {
          String fullName = PREFIX + service.getName();
          if (loader == null)
            configs = ClassLoader.getSystemResources(fullName);
          else
            configs = loader.getResources(fullName);
        } catch (IOException x) {
          fail(service, "Error locating configuration files", x);
        }
      }
      while ((pending == null) || !pending.hasNext()) {
        if (!configs.hasMoreElements()) {
          return false;
        }
        pending = parse(service, configs.nextElement());
      }
      nextName = pending.next();
      return true;
    }

    private S nextService() {
      if (!hasNextService())
        throw new NoSuchElementException();
      String cn = nextName;
      nextName = null;
      Class<?> c = null;
      try {
        c = Class.forName(cn, false, loader);
      } catch (ClassNotFoundException x) {
        fail(service,
           "Provider " + cn + " not found");
      }
      if (!service.isAssignableFrom(c)) {
        fail(service,
           "Provider " + cn + " not a subtype");
      }
      try {
        S p = service.cast(c.newInstance());
        providers.put(cn, p);
        return p;
      } catch (Throwable x) {
        fail(service,
           "Provider " + cn + " could not be instantiated",
           x);
      }
      throw new Error();     // This cannot happen
    }

    public boolean hasNext() {
      if (acc == null) {
        return hasNextService();
      } else {
        PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
          public Boolean run() { return hasNextService(); }
        };
        return AccessController.doPrivileged(action, acc);
      }
    }

  hasNext查找實(shí)現(xiàn)類,并指定了類路徑:

private static final String PREFIX = "META-INF/services/";

  具體查找操作看這里:

pending = parse(service, configs.nextElement());

  next則是實(shí)例化加載到的實(shí)現(xiàn)類,使用反射Class.forName加載類、newInstance實(shí)例化對象。

以上就是Java SPI的簡單小實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于Java SPI實(shí)例的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mybatis-plus對單表操作的封裝實(shí)現(xiàn)

    Mybatis-plus對單表操作的封裝實(shí)現(xiàn)

    本文詳細(xì)介紹了MyBatis-Plus單表操作,包括自定義SQL、邏輯刪除、樂觀鎖、全局?jǐn)r截器和代碼生成器等,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • Java四種線程池的使用詳解

    Java四種線程池的使用詳解

    本篇文章主要介紹了Java四種線程池的使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java中使用Closeable接口自動關(guān)閉資源詳解

    Java中使用Closeable接口自動關(guān)閉資源詳解

    這篇文章主要介紹了Java中使用Closeable接口自動關(guān)閉資源詳解,Closeable接口繼承于AutoCloseable,主要的作用就是自動的關(guān)閉資源,其中close()方法是關(guān)閉流并且釋放與其相關(guān)的任何方法,如果流已被關(guān)閉,那么調(diào)用此方法沒有效果,需要的朋友可以參考下
    2023-12-12
  • JavaGUI菜單欄與文本和密碼及文本域組件使用詳解

    JavaGUI菜單欄與文本和密碼及文本域組件使用詳解

    這篇文章主要介紹了JavaGUI菜單欄與文本和密碼及文本域組件使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-03-03
  • Java日期工具類操作字符串Date和LocalDate互轉(zhuǎn)

    Java日期工具類操作字符串Date和LocalDate互轉(zhuǎn)

    這篇文章主要介紹了Java日期工具類操作字符串Date和LocalDate互轉(zhuǎn),文章首先通過需要先引入坐標(biāo)展開主題的相關(guān)內(nèi)容介紹,需要的朋友可以參一下
    2022-06-06
  • SpringBoot的HTTPS配置實(shí)現(xiàn)

    SpringBoot的HTTPS配置實(shí)現(xiàn)

    本文主要介紹了SpringBoot的HTTPS配置實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Java8中的default關(guān)鍵字詳解

    Java8中的default關(guān)鍵字詳解

    這篇文章主要介紹了Java8中的default關(guān)鍵字詳解,在實(shí)現(xiàn)某個接口的時候,需要實(shí)現(xiàn)該接口所有的方法,這個時候default關(guān)鍵字就派上用場了。通過default關(guān)鍵字定義的方法,集成該接口的方法不需要去實(shí)現(xiàn)該方法,需要的朋友可以參考下
    2023-08-08
  • Filter在springboot中的使用方法詳解

    Filter在springboot中的使用方法詳解

    這篇文章主要介紹了Filter在springboot中的使用方法詳解,filter(過濾器)作用于在intreceptor(攔截器)之前,不像intreceptor一樣依賴于springmvc框架,只需要依賴于serverlet,需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)七牛云文件圖片上傳下載

    Java實(shí)現(xiàn)七牛云文件圖片上傳下載

    本文主要介紹了Java實(shí)現(xiàn)七牛云文件圖片上傳下載,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java性能調(diào)優(yōu)及排查方式

    Java性能調(diào)優(yōu)及排查方式

    這篇文章主要介紹了Java性能調(diào)優(yōu)及排查方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論

文成县| 永胜县| 涡阳县| 陇川县| 海原县| 隆昌县| 陇川县| 睢宁县| 通辽市| 宝山区| 自贡市| 沁水县| 娄底市| 长白| 安义县| 三明市| 肇州县| 南木林县| 马尔康县| 蛟河市| 通许县| 永胜县| 武定县| 麦盖提县| 安达市| 荥阳市| 永安市| 南宁市| 贺州市| 济南市| 泰安市| 达拉特旗| 衡东县| 玉山县| 江都市| 盱眙县| 张家口市| 长海县| 攀枝花市| 滕州市| 拉萨市|