<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      JDK中「SPI」原理分析

      基于【JDK1.8】

      一、SPI簡介

      1、概念

      SPI即service-provider-interface的簡寫;

      JDK內置的服務提供加載機制,可以為服務接口加載實現類,解耦是其核心思想,也是很多框架和組件的常用手段;

      2、入門案例

      2.1 定義接口

      就是普通的接口,在SPI的機制中稱為【service】,即服務;

      public interface Animal {
          String animalName () ;
      }
      

      2.2 兩個實現類

      提供兩個模擬用來測試,就是普通的接口實現類,在SPI的機制中稱為【service-provider】即服務提供方;

      CatAnimal實現類;

      public class CatAnimal implements Animal {
          @Override
          public String animalName() {
              System.out.println("Cat-Animal:布偶貓");
              return "Ragdoll";
          }
      }
      

      DogAnimal實現類;

      public class DogAnimal implements Animal {
          @Override
          public String animalName() {
              System.out.println("Dog-Animal:哈士奇");
              return "husky";
          }
      }
      

      2.3 配置文件

      文件目錄:在代碼工程中創建META-INF.services文件夾;

      文件命名:butte.program.basics.spi.inf.Animal,即全限定接口名稱;

      文件內容:添加相應實現類的全限定命名;

      butte.program.basics.spi.impl.CatAnimal
      butte.program.basics.spi.impl.DogAnimal
      

      2.4 測試代碼

      通過ServiceLoader加載配置文件中指定的服務實現類,然后遍歷并調用Animal接口方法,從而執行不同服務提供方的具體邏輯;

      public class SpiAnaly {
          public static void main(String[] args) {
              ServiceLoader<Animal> serviceLoader = ServiceLoader.load(Animal.class);
              Iterator<Animal> animalIterator = serviceLoader.iterator();
              while(animalIterator.hasNext()) {
                  Animal animal = animalIterator.next();
                  System.out.println("animal-name:" + animal.animalName());
              }
          }
      }
      

      結果輸出

      Cat-Animal:布偶貓 \n animal-name:ragdoll
      Dog-Animal:哈士奇 \n animal-name:husky
      

      二、原理分析

      1、ServiceLoader結構

      很顯然,分析SPI機制的原理,從ServiceLoader源碼中load方法切入即可,但是需要先從核心類的結構開始分析;

      public final class ServiceLoader<S> implements Iterable<S> {
          // 配置文件目錄
          private static final String PREFIX = "META-INF/services/";
          // 表示正在加載的服務的類或接口
          private final Class<S> service;
          // 類加載器用來定位,加載,實例化服務提供方
          private final ClassLoader loader;
          // 創建ServiceLoader時采用的訪問控制上下文
          private final AccessControlContext acc;
          // 按實例化的順序緩存服務提供方
          private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
          // 惰性查找迭代器
          private LazyIterator lookupIterator;
          /**
           * service:表示服務的接口或抽象類
           * loader: 類加載器
           */
          public static <S> ServiceLoader<S> load(Class<S> service) {
              ClassLoader cl = Thread.currentThread().getContextClassLoader();
              return ServiceLoader.load(service, cl);
          }
          /**
           * ServiceLoader構造方法
           */
          private ServiceLoader(Class<S> svc, ClassLoader cl) {
              loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
              acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
              reload();
          }
          public void reload() {
              providers.clear();
              // 實例化迭代器
              lookupIterator = new LazyIterator(service, loader);
          }
          public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader) {
              return new ServiceLoader<>(service, loader);
          }
      
          private class LazyIterator implements Iterator<S> {
              // 服務接口
              Class<S> service;
              // 類加載器
              ClassLoader loader;
              // 實現類URL
              Enumeration<URL> configs = null;
              // 實現類全名
              Iterator<String> pending = null;
              // 下個實現類全名
              String nextName = null;
          }
      }
      

      斷點截圖:

      2、iterator迭代方法

      ServiceLoader類的迭代器方法中,實際使用的是LazyIterator內部類的方法;

      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();
              }
          };
      }
      

      3、hasNextService方法

      從上面迭代方法的源碼中可知,最終執行的是LazyIterator#hasNextService判斷方法,該方法通過解析最終會得到實現類的全限定名稱;

      private class LazyIterator implements Iterator<S> {
          private boolean hasNextService() {
              // 1、拼接名稱
              String fullName = PREFIX + service.getName();
              // 2、加載資源文件
              configs = loader.getResources(fullName);
              // 3、解析文件內容
              pending = parse(service, configs.nextElement());
              nextName = pending.next();
              return true;
          }
      }
      

      斷點截圖:

      4、nextService方法

      迭代器的next方法最終執行的是LazyIterator#nextService獲取方法,會基于上面hasNextService方法獲取的實現類全限定名稱,獲取其Class對象,進而得到實例化對象,緩存并返回;

      private class LazyIterator implements Iterator<S> {
          private S nextService() {
              // 1、通過全限定命名獲取Class對象
              String cn = nextName;
              Class<?> c = Class.forName(cn, false, loader);
              // 2、實例化對象
              S p = service.cast(c.newInstance());
              // 3、放入緩存并返回該對象
              providers.put(cn, p);
              return p;
          }
      }
      

      斷點截圖:

      三、SPI實踐

      1、Driver驅動接口

      在JDK中提供了數據庫驅動接口java.sql.Driver,無論是MySQL驅動包還是Druid連接池,都提供了該接口的實現類,通過SPI機制可以加載到這些驅動實現類;

      public class DriverManager {
          private static void loadInitialDrivers() {
              AccessController.doPrivileged(new PrivilegedAction<Void>() {
                  public Void run() {
                      ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(java.sql.Driver.class);
                      Iterator<Driver> driversIterator = loadedDrivers.iterator();
                  }
              });
          }
      }
      

      斷點截圖:

      2、Slf4j日志接口

      SLF4J是門面模式的日志組件,提供了標準的日志服務SLF4JServiceProvider接口,在LogFactory日志工廠類中,負責加載具體的日志實現類,比如常用的Log4j或Logback日志組件;

      public final class LoggerFactory {
          static List<SLF4JServiceProvider> findServiceProviders() {
              // 服務加載
              ClassLoader classLoaderOfLoggerFactory = org.slf4j.LoggerFactory.class.getClassLoader();
              // 重點看該方法:【getServiceLoader()】
              ServiceLoader<SLF4JServiceProvider> serviceLoader = getServiceLoader(classLoaderOfLoggerFactory);
              // 迭代方法
              List<SLF4JServiceProvider> providerList = new ArrayList();
              Iterator<SLF4JServiceProvider> iterator = serviceLoader.iterator();
              while(iterator.hasNext()) {
                  safelyInstantiate(providerList, iterator);
              }
              return providerList;
          }
      }
      

      斷點截圖:

      四、參考源碼

      文檔倉庫:
      https://gitee.com/cicadasmile/butte-java-note
      
      應用倉庫:
      https://gitee.com/cicadasmile/butte-flyer-parent
      
      posted @ 2023-08-05 11:51  七號樓  閱讀(636)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久99国产精品久久99小说| 国产精品制服丝袜无码| 国产午夜鲁丝片av无码| 丰满的少妇一区二区三区 | 可以在线观看的亚洲视频| av资源在线看免费观看| 久久丁香五月天综合网| 高清无码爆乳潮喷在线观看| 国内精品久久人妻无码不卡| 亚欧洲乱码视频一二三区| 亚欧洲乱码视频在线专区| 久久99九九精品久久久久蜜桃| 色一情一乱一区二区三区码| 无码高潮爽到爆的喷水视频| 亚洲精品一区国产精品| av偷拍亚洲一区二区三区| 国产精品久久久久影院老司| 久久精品国产亚洲av电影| 亚洲综合成人一区二区三区| 菠萝菠萝蜜午夜视频在线播放观看| 日韩AV片无码一区二区不卡| 国内精品视频区在线2021 | 久久久国产成人一区二区 | 亚洲国产美女精品久久久| 国产精品一区在线蜜臀| 国产欧亚州美日韩综合区| 国产乱码精品一区二区三| 亚洲综合伊人久久大杳蕉| 久久精品A一国产成人免费网站 | 欧美精品18videosex性欧美| 女人张开腿无遮无挡视频| 中文字幕国产精品日韩| 亚洲中文字幕一区二区| 达孜县| 色欧美片视频在线观看| 日韩精品一区二区三区激情| 最新亚洲人成网站在线观看| 亚洲综合av一区二区三区| 最新亚洲人成无码WWW| 亚洲性线免费观看视频成熟| 久久精品丝袜高跟鞋|