鴻蒙OS ServiceLoader

2022-08-04 17:10 更新

ServiceLoader

java.lang.Object

|---java.util.ServiceLoader<S&

public final class ServiceLoader<S>
extends Object
implements Iterable<S>

一個(gè)簡(jiǎn)單的服務(wù)提供者加載工具。

服務(wù)是一組眾所周知的接口和(通常是抽象的)類。 服務(wù)提供者是服務(wù)的具體實(shí)現(xiàn)。 提供者中的類通常實(shí)現(xiàn)服務(wù)本身中定義的類的接口和子類。 服務(wù)提供者可以以擴(kuò)展的形式安裝在 Java 平臺(tái)的實(shí)現(xiàn)中,即將 jar 文件放置在任何常用的擴(kuò)展目錄中。 還可以通過將提供程序添加到應(yīng)用程序的類路徑或通過某些其他特定于平臺(tái)的方式來使提供程序可用。

出于加載的目的,服務(wù)由單一類型表示,即單一接口或抽象類。 (可以使用具體類,但不建議這樣做。)給定服務(wù)的提供者包含一個(gè)或多個(gè)具體類,這些具體類使用提供者特定的數(shù)據(jù)和代碼擴(kuò)展此服務(wù)類型。 提供者類通常不是整個(gè)提供者本身,而是一個(gè)代理,它包含足夠的信息來決定提供者是否能夠滿足特定請(qǐng)求以及可以按需創(chuàng)建實(shí)際提供者的代碼。 提供者類的細(xì)節(jié)往往是高度特定于服務(wù)的; 沒有一個(gè)類或接口可以統(tǒng)一它們,所以這里沒有定義這樣的類型。 此工具強(qiáng)制執(zhí)行的唯一要求是提供程序類必須具有零參數(shù)構(gòu)造函數(shù),以便它們可以在加載期間被實(shí)例化。

通過在資源目錄 META-INF/services 中放置提供者配置文件來識(shí)別服務(wù)提供者。 該文件的名稱是服務(wù)類型的完全限定二進(jìn)制名稱。 該文件包含具體提供程序類的完全限定二進(jìn)制名稱列表,每行一個(gè)。 每個(gè)名稱周圍的空格和制表符以及空白行將被忽略。 注釋字符為'#'('\u0023', NUMBER SIGN); 在每一行中,第一個(gè)注釋字符之后的所有字符都將被忽略。 該文件必須以 UTF-8 編碼。

如果一個(gè)特定的具體提供者類在多個(gè)配置文件中被命名,或者在同一個(gè)配置文件中被命名不止一次,那么重復(fù)的將被忽略。 命名特定提供者的配置文件不必與提供者本身位于相同的 jar 文件或其他分發(fā)單元中。 必須可以從最初查詢配置文件的同一個(gè)類加載器訪問提供程序; 請(qǐng)注意,這不一定是實(shí)際加載文件的類加載器。

提供者的定位和實(shí)例化是惰性的,即按需。 服務(wù)加載器維護(hù)到目前為止已加載的提供程序的緩存。 迭代器方法的每次調(diào)用都會(huì)返回一個(gè)迭代器,它首先按實(shí)例化順序產(chǎn)生緩存的所有元素,然后延遲定位并實(shí)例化任何剩余的提供者,依次將每個(gè)提供者添加到緩存中。 可以通過 reload 方法清除緩存。

服務(wù)加載程序總是在調(diào)用者的安全上下文中執(zhí)行。 受信任的系統(tǒng)代碼通常應(yīng)該從特權(quán)安全上下文中調(diào)用此類中的方法以及它們返回的迭代器的方法。

此類的實(shí)例對(duì)于多個(gè)并發(fā)線程的使用是不安全的。

除非另有說明,否則將 null 參數(shù)傳遞給此類中的任何方法都將導(dǎo)致拋出 NullPointerException。

示例 假設(shè)我們有一個(gè)服務(wù)類型 com.example.CodecSet,它旨在表示某些協(xié)議的編碼器/解碼器對(duì)集合。 在這種情況下,它是一個(gè)具有兩個(gè)抽象方法的抽象類:

 public abstract Encoder getEncoder(String encodingName);
 public abstract Decoder getDecoder(String encodingName);

如果提供者不支持給定的編碼,每個(gè)方法都會(huì)返回一個(gè)適當(dāng)?shù)膶?duì)象或 null。 典型的供應(yīng)商支持不止一種編碼。

如果 com.example.impl.StandardCodecs 是 CodecSet 服務(wù)的實(shí)現(xiàn),那么它的 jar 文件還包含一個(gè)名為

 META-INF/services/com.example.CodecSet

該文件包含一行:

 com.example.impl.StandardCodecs    # Standard codecs

CodecSet 類在初始化時(shí)創(chuàng)建并保存單個(gè)服務(wù)實(shí)例:

 private static ServiceLoader<CodecSet> codecSetLoader
     = ServiceLoader.load(CodecSet.class);

為了找到給定編碼名稱的編碼器,它定義了一個(gè)靜態(tài)工廠方法,該方法遍歷已知和可用的提供程序,僅在找到合適的編碼器或用完提供程序時(shí)返回。

 public static Encoder getEncoder(String encodingName) {
     for (CodecSet cp : codecSetLoader) {
         Encoder enc = cp.getEncoder(encodingName);
         if (enc != null)
             return enc;
     }
     return null;
 }

getDecoder 方法的定義類似。

使用說明 如果用于加載提供程序的類加載器的類路徑包含遠(yuǎn)程網(wǎng)絡(luò) URL,則在搜索提供程序配置文件的過程中將取消引用這些 URL。

此活動(dòng)是正常的,盡管它可能會(huì)導(dǎo)致在 Web 服務(wù)器日志中創(chuàng)建令人費(fèi)解的條目。但是,如果未正確配置 Web 服務(wù)器,則此活動(dòng)可能會(huì)導(dǎo)致提供程序加載算法虛假失敗。

當(dāng)請(qǐng)求的資源不存在時(shí),Web 服務(wù)器應(yīng)返回 HTTP 404(未找到)響應(yīng)。但是,有時(shí) Web 服務(wù)器被錯(cuò)誤地配置為在這種情況下返回 HTTP 200 (OK) 響應(yīng)以及有用的 HTML 錯(cuò)誤頁面。當(dāng)此類嘗試將 HTML 頁面解析為提供程序配置文件時(shí),這將導(dǎo)致拋出 ServiceConfigurationError。此問題的最佳解決方案是修復(fù)錯(cuò)誤配置的 Web 服務(wù)器以返回正確的響應(yīng)代碼 (HTTP 404) 以及 HTML 錯(cuò)誤頁面。

方法總結(jié)

修飾符和類型 方法 描述
IteratorS iterator() 延遲加載此加載程序服務(wù)的可用提供程序。
static <S> ServiceLoader<S> load(Class<S> service) 使用當(dāng)前線程的上下文類加載器為給定的服務(wù)類型創(chuàng)建一個(gè)新的服務(wù)加載器。
static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) 為給定的服務(wù)類型和類加載器創(chuàng)建一個(gè)新的服務(wù)加載器。
static <S> ServiceLoader<S> loadInstalled(Class<S> service) 使用擴(kuò)展類加載器為給定的服務(wù)類型創(chuàng)建一個(gè)新的服務(wù)加載器。
void reload() 清除此加載器的提供程序緩存,以便重新加載所有提供程序。
String toString() 返回描述此服務(wù)的字符串。
從接口 java.lang.Iterable 繼承的方法
forEach, spliterator
從類 java.lang.Object 繼承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

方法詳情

reload

public void reload()

清除此加載器的提供程序緩存,以便重新加載所有提供程序。

調(diào)用此方法后,迭代器方法的后續(xù)調(diào)用將懶惰地從頭開始查找并實(shí)例化提供程序,就像新創(chuàng)建的加載程序所做的那樣。

此方法適用于可以將新提供程序安裝到正在運(yùn)行的 Java 虛擬機(jī)中的情況。

iterator

public IteratorS iterator()

延遲加載此加載程序服務(wù)的可用提供程序。

此方法返回的迭代器首先按實(shí)例化順序生成提供程序緩存的所有元素。 然后它會(huì)延遲加載并實(shí)例化任何剩余的提供者,依次將每個(gè)提供者添加到緩存中。

為了實(shí)現(xiàn)惰性,解析可用提供程序配置文件和實(shí)例化提供程序的實(shí)際工作必須由迭代器本身完成。 因此,如果提供程序配置文件違反了指定格式,或者如果它命名了無法找到和實(shí)例化的提供程序類,或者如果實(shí)例化類的結(jié)果不能分配給服務(wù)類型,則它的 hasNext 和 next 方法可以拋出 ServiceConfigurationError ,或者在定位和實(shí)例化下一個(gè)提供程序時(shí)引發(fā)任何其他類型的異?;蝈e(cuò)誤。 要編寫健壯的代碼,只需要在使用服務(wù)迭代器時(shí)捕獲 ServiceConfigurationError。

如果拋出這樣的錯(cuò)誤,那么迭代器的后續(xù)調(diào)用將盡最大努力定位和實(shí)例化下一個(gè)可用的提供程序,但通常不能保證這樣的恢復(fù)。

設(shè)計(jì)說明 在這些情況下拋出錯(cuò)誤可能看起來很極端。 這種行為的基本原理是格式錯(cuò)誤的提供程序配置文件(如格式錯(cuò)誤的類文件)表明 Java 虛擬機(jī)的配置或使用方式存在嚴(yán)重問題。 因此,最好拋出錯(cuò)誤而不是嘗試恢復(fù),或者更糟糕的是,靜默失敗。

此方法返回的迭代器不支持移除。 調(diào)用它的 remove 方法將導(dǎo)致拋出 UnsupportedOperationException。

指定者:

接口 IterableS 中的迭代器

返回:

延遲加載此加載器服務(wù)的提供程序的迭代器

load

public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)

為給定的服務(wù)類型和類加載器創(chuàng)建一個(gè)新的服務(wù)加載器。

類型參數(shù):

類型參數(shù)名稱 類型參數(shù)描述
S 服務(wù)類型的類

參數(shù):

參數(shù)名稱 參數(shù)描述
service 表示服務(wù)的接口或抽象類
loader 用于加載提供程序配置文件和提供程序類的類加載器,如果要使用系統(tǒng)類加載器(或者,如果失敗,則為引導(dǎo)類加載器),則為 null

返回:

一個(gè)新的服務(wù)加載器

load

public static <S> ServiceLoader<S> load(Class<S> service)

使用當(dāng)前線程的上下文類加載器為給定的服務(wù)類型創(chuàng)建一個(gè)新的服務(wù)加載器。

調(diào)用表單的這種便捷方法

 ServiceLoader.load(service)

相當(dāng)于

 ServiceLoader.load(service,
                    Thread.currentThread().getContextClassLoader())

類型參數(shù):

類型參數(shù)名稱 類型參數(shù)描述
S 服務(wù)類型的類

參數(shù):

參數(shù)名稱 參數(shù)描述
service 表示服務(wù)的接口或抽象類

返回:

一個(gè)新的服務(wù)加載器

loadInstalled

public static <S> ServiceLoader<S> loadInstalled(Class<S> service)

使用擴(kuò)展類加載器為給定的服務(wù)類型創(chuàng)建一個(gè)新的服務(wù)加載器。

這個(gè)方便的方法只是簡(jiǎn)單的定位擴(kuò)展類加載器,調(diào)用它extClassLoader,然后返回

 ServiceLoader.load(service, extClassLoader)

如果找不到擴(kuò)展類加載器,則使用系統(tǒng)類加載器; 如果沒有系統(tǒng)類加載器,則使用引導(dǎo)類加載器。

此方法旨在僅在需要已安裝的提供程序時(shí)使用。 生成的服務(wù)只會(huì)查找并加載已安裝到當(dāng)前 Java 虛擬機(jī)中的提供程序; 應(yīng)用程序類路徑上的提供者將被忽略。

類型參數(shù):

類型參數(shù)名稱 類型參數(shù)描述
S 服務(wù)類型的類

參數(shù):

參數(shù)名稱 參數(shù)描述
service 表示服務(wù)的接口或抽象類

返回:

一個(gè)新的服務(wù)加載器

toString

public String toString()

返回描述此服務(wù)的字符串。

覆蓋:

類 Object 中的 toString

返回:

描述性字符串

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)