{"id":10006201,"date":"2022-08-15T10:43:24","date_gmt":"2022-08-15T02:43:24","guid":{"rendered":"https:\/\/ityet.com\/?p=10006201"},"modified":"2022-08-15T10:43:24","modified_gmt":"2022-08-15T02:43:24","slug":"%e4%b8%80%e6%96%87%e8%ae%b2%e9%80%8fjava%e6%a0%b8%e5%bf%83%e6%8a%80%e6%9c%af%e4%b9%8b%e9%ab%98%e5%8f%af%e6%89%a9%e5%b1%95%e5%88%a9%e5%99%a8spi","status":"publish","type":"post","link":"https:\/\/itmax.cn\/?p=10006201","title":{"rendered":"\u4e00\u6587\u8bb2\u900fJava\u6838\u5fc3\u6280\u672f\u4e4b\u9ad8\u53ef\u6269\u5c55\u5229\u5668SPI"},"content":{"rendered":"<p><strong>\u5927\u5bb6\u597d\uff0c\u6211\u662f\u51b0\u6cb3~~<\/strong><\/p>\n<h2>SPI\u7684\u6982\u5ff5<\/h2>\n<p><strong><code>JAVA SPI<\/code> = \u57fa\u4e8e\u63a5\u53e3\u7684\u7f16\u7a0b\uff0b\u7b56\u7565\u6a21\u5f0f\uff0b\u914d\u7f6e\u6587\u4ef6 \u7684\u52a8\u6001\u52a0\u8f7d\u673a\u5236<\/strong><\/p>\n<h2>SPI\u7684\u4f7f\u7528\u573a\u666f<\/h2>\n<p>Java\u662f\u4e00\u79cd\u9762\u5411\u5bf9\u8c61\u8bed\u8a00\uff0c\u867d\u7136Java8\u5f00\u59cb\u652f\u6301\u51fd\u6570\u5f0f\u7f16\u7a0b\u548cStream\uff0c\u4f46\u662f\u603b\u4f53\u6765\u8bf4\uff0c\u8fd8\u662f\u9762\u5411\u5bf9\u8c61\u7684\u8bed\u8a00\u3002\u5728\u4f7f\u7528Java\u8fdb\u884c\u9762\u5411\u5bf9\u8c61\u5f00\u53d1\u65f6\uff0c\u4e00\u822c\u4f1a\u63a8\u8350\u4f7f\u7528\u57fa\u4e8e\u63a5\u53e3\u7684\u7f16\u7a0b\uff0c\u7a0b\u5e8f\u7684\u6a21\u5757\u4e0e\u6a21\u5757\u4e4b\u524d\u4e0d\u4f1a\u76f4\u63a5\u8fdb\u884c\u5b9e\u73b0\u7c7b\u7684\u786c\u7f16\u7801\u3002\u800c\u5728\u5b9e\u9645\u7684\u5f00\u53d1\u8fc7\u7a0b\u4e2d\uff0c\u5f80\u5f80\u4e00\u4e2a\u63a5\u53e3\u4f1a\u6709\u591a\u4e2a\u5b9e\u73b0\u7c7b\uff0c\u5404\u5b9e\u73b0\u7c7b\u8981\u4e48\u5b9e\u73b0\u7684\u903b\u8f91\u4e0d\u540c\uff0c\u8981\u4e48\u4f7f\u7528\u7684\u65b9\u5f0f\u4e0d\u540c\uff0c\u8fd8\u6709\u7684\u5c31\u662f\u5b9e\u73b0\u7684\u6280\u672f\u4e0d\u540c\u3002\u4e3a\u4e86\u4f7f\u8c03\u7528\u65b9\u5728\u8c03\u7528\u63a5\u53e3\u7684\u65f6\u5019\uff0c\u660e\u786e\u7684\u77e5\u9053\u81ea\u5df1\u8c03\u7528\u7684\u662f\u63a5\u53e3\u7684\u54ea\u4e2a\u5b9e\u73b0\u7c7b\uff0c\u6216\u8005\u8bf4\u4e3a\u4e86\u5b9e\u73b0\u5728\u6a21\u5757\u88c5\u914d\u7684\u65f6\u5019\u4e0d\u7528\u5728\u7a0b\u5e8f\u91cc\u52a8\u6001\u6307\u660e\uff0c\u8fd9\u5c31\u9700\u8981\u4e00\u79cd\u670d\u52a1\u53d1\u73b0\u673a\u5236\u3002Java\u4e2d\u7684SPI\u52a0\u8f7d\u673a\u5236\u80fd\u591f\u6ee1\u8db3\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u5b83\u80fd\u591f\u81ea\u52a8\u5bfb\u627e\u67d0\u4e2a\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u3002<\/p>\n<p><strong>\u5927\u91cf\u7684\u6846\u67b6\u4f7f\u7528\u4e86Java\u7684SPI\u6280\u672f\uff0c\u5982\u4e0b\uff1a<\/strong><\/p>\n<p>\uff081\uff09JDBC\u52a0\u8f7d\u4e0d\u540c\u7c7b\u578b\u7684\u6570\u636e\u5e93\u9a71\u52a8<br \/> \uff082\uff09\u65e5\u5fd7\u95e8\u9762\u63a5\u53e3\u5b9e\u73b0\u7c7b\u52a0\u8f7d\uff0cSLF4J\u52a0\u8f7d\u4e0d\u540c\u63d0\u4f9b\u5546\u7684\u65e5\u5fd7\u5b9e\u73b0\u7c7b<br \/> \uff083\uff09Spring\u4e2d\u5927\u91cf\u4f7f\u7528\u4e86SPI<\/p>\n<ul>\n<li>\u5bf9servlet3.0\u89c4\u8303<\/li>\n<li>\u5bf9ServletContainerInitializer\u7684\u5b9e\u73b0<\/li>\n<li>\u81ea\u52a8\u7c7b\u578b\u8f6c\u6362Type Conversion SPI(Converter SPI\u3001Formatter SPI)\u7b49<\/li>\n<\/ul>\n<p>\uff084\uff09Dubbo\u91cc\u9762\u6709\u5f88\u591a\u4e2a\u7ec4\u4ef6\uff0c\u6bcf\u4e2a\u7ec4\u4ef6\u5728\u6846\u67b6\u4e2d\u90fd\u662f\u4ee5\u63a5\u53e3\u7684\u5f62\u6210\u62bd\u8c61\u51fa\u6765\uff01\u5177\u4f53\u7684\u5b9e\u73b0\u53c8\u5206\u5f88\u591a\u79cd\uff0c\u5728\u7a0b\u5e8f\u6267\u884c\u65f6\u6839\u636e\u7528\u6237\u7684\u914d\u7f6e\u6765\u6309\u9700\u53d6\u63a5\u53e3\u7684\u5b9e\u73b0<\/p>\n<h2>SPI\u7684\u4f7f\u7528<\/h2>\n<p>\u5f53\u670d\u52a1\u7684\u63d0\u4f9b\u8005\uff0c\u63d0\u4f9b\u4e86\u63a5\u53e3\u7684\u4e00\u79cd\u5b9e\u73b0\u540e\uff0c\u9700\u8981\u5728Jar\u5305\u7684<strong>META-INF\/services\/<\/strong>\u76ee\u5f55\u4e0b\uff0c\u521b\u5efa\u4e00\u4e2a\u4ee5\u63a5\u53e3\u7684\u540d\u79f0\uff08\u5305\u540d.\u63a5\u53e3\u540d\u7684\u5f62\u5f0f\uff09\u547d\u540d\u7684\u6587\u4ef6\uff0c\u5728\u6587\u4ef6\u4e2d\u914d\u7f6e\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\uff08\u5b8c\u6574\u7684\u5305\u540d+\u7c7b\u540d\uff09\u3002<\/p>\n<p>\u5f53\u5916\u90e8\u7a0b\u5e8f\u901a\u8fc7<strong>java.util.ServiceLoader<\/strong>\u7c7b\u88c5\u8f7d\u8fd9\u4e2a\u63a5\u53e3\u65f6\uff0c\u5c31\u80fd\u591f\u901a\u8fc7\u8be5Jar\u5305\u7684<strong>META\/Services\/<\/strong>\u76ee\u5f55\u91cc\u7684\u914d\u7f6e\u6587\u4ef6\u627e\u5230\u5177\u4f53\u7684\u5b9e\u73b0\u7c7b\u540d\uff0c\u88c5\u8f7d\u5b9e\u4f8b\u5316\uff0c\u5b8c\u6210\u6ce8\u5165\u3002\u540c\u65f6\uff0cSPI\u7684\u89c4\u8303\u89c4\u5b9a\u4e86\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u5fc5\u987b\u6709\u4e00\u4e2a\u65e0\u53c2\u6784\u9020\u65b9\u6cd5\u3002<\/p>\n<p>SPI\u4e2d\u67e5\u627e\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u662f\u901a\u8fc7<strong>java.util.ServiceLoader<\/strong>\uff0c\u800c\u5728<strong>java.util.ServiceLoader<\/strong>\u7c7b\u4e2d\u6709\u4e00\u884c\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre><code class=\"java\">\/\/ \u52a0\u8f7d\u5177\u4f53\u5b9e\u73b0\u7c7b\u4fe1\u606f\u7684\u524d\u7f00\uff0c\u4e5f\u5c31\u662f\u4ee5\u63a5\u53e3\u547d\u540d\u7684\u6587\u4ef6\u9700\u8981\u653e\u5230Jar\u5305\u4e2d\u7684META-INF\/services\/\u76ee\u5f55\u4e0b\nprivate static final String PREFIX = &quot;META-INF\/services\/&quot;;<\/code><\/pre>\n<p>\u8fd9\u4e5f\u5c31\u662f\u8bf4\uff0c\u6211\u4eec\u5fc5\u987b\u5c06\u63a5\u53e3\u7684\u914d\u7f6e\u6587\u4ef6\u5199\u5230Jar\u5305\u7684<strong>META\/Services\/<\/strong>\u76ee\u5f55\u4e0b\u3002<\/p>\n<h2>SPI\u5b9e\u4f8b<\/h2>\n<p>\u8fd9\u91cc\uff0c\u7ed9\u51fa\u4e00\u4e2a\u7b80\u5355\u7684SPI\u4f7f\u7528\u5b9e\u4f8b\uff0c\u6f14\u793a\u5728Java\u7a0b\u5e8f\u4e2d\u5982\u4f55\u4f7f\u7528SPI\u52a8\u6001\u52a0\u8f7d\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u3002<\/p>\n<p>\u6ce8\u610f\uff1a\u5b9e\u4f8b\u662f\u57fa\u4e8eJava8\u8fdb\u884c\u5f00\u53d1\u7684\u3002<\/p>\n<h3>1.\u521b\u5efaMaven\u9879\u76ee<\/h3>\n<p>\u5728IDEA\u4e2d\u521b\u5efaMaven\u9879\u76eespi-demo\uff0c\u5982\u4e0b\uff1a<\/p>\n<p><img decoding=\"async\" referrerpolicy=\"no-referrer\" src=\"https:\/\/segmentfault.com\/img\/remote\/1460000038242160\" alt=\"img\" title=\"img\" loading=\"lazy\"><\/p>\n<h3>2.\u7f16\u8f91pom.xml<\/h3>\n<pre><code class=\"html\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n&lt;project xmlns=&quot;http:\/\/maven.apache.org\/POM\/4.0.0&quot;\n         xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;\n         xsi:schemaLocation=&quot;http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd&quot;&gt;\n\n    &lt;artifactId&gt;spi-demo&lt;\/artifactId&gt;\n    &lt;groupId&gt;io.binghe.spi&lt;\/groupId&gt;\n    &lt;packaging&gt;jar&lt;\/packaging&gt;\n    &lt;version&gt;1.0.0-SNAPSHOT&lt;\/version&gt;\n    &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n    &lt;build&gt;\n        &lt;plugins&gt;\n            &lt;plugin&gt;\n                &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n                &lt;artifactId&gt;spring-boot-maven-plugin&lt;\/artifactId&gt;\n            &lt;\/plugin&gt;\n            &lt;plugin&gt;\n                &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n                &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n                &lt;version&gt;3.6.0&lt;\/version&gt;\n                &lt;configuration&gt;\n                    &lt;source&gt;1.8&lt;\/source&gt;\n                    &lt;target&gt;1.8&lt;\/target&gt;\n                &lt;\/configuration&gt;\n            &lt;\/plugin&gt;\n        &lt;\/plugins&gt;\n    &lt;\/build&gt;\n&lt;\/project&gt;<\/code><\/pre>\n<h3>3.\u521b\u5efa\u7c7b\u52a0\u8f7d\u5de5\u5177\u7c7b<\/h3>\n<p>\u5728io.binghe.spi.loader\u5305\u4e0b\u521b\u5efaMyServiceLoader\uff0cMyServiceLoader\u7c7b\u4e2d\u76f4\u63a5\u8c03\u7528JDK\u7684ServiceLoader\u7c7b\u52a0\u8f7dClass\u3002\u4ee3\u7801\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<pre><code class=\"java\">package io.binghe.spi.loader;\n\nimport java.util.ServiceLoader;\n\n\/**\n * @author binghe\n * @version 1.0.0\n * @description \u7c7b\u52a0\u8f7d\u5de5\u5177\n *\/\npublic class MyServiceLoader {\n\n    \/**\n     * \u4f7f\u7528SPI\u673a\u5236\u52a0\u8f7d\u6240\u6709\u7684Class\n     *\/\n    public static &lt;S&gt; ServiceLoader&lt;S&gt; loadAll(final Class&lt;S&gt; clazz) {\n        return ServiceLoader.load(clazz);\n    }\n}<\/code><\/pre>\n<h3>4.\u521b\u5efa\u63a5\u53e3<\/h3>\n<p>\u5728io.binghe.spi.service\u5305\u4e0b\u521b\u5efa\u63a5\u53e3MyService\uff0c\u4f5c\u4e3a\u6d4b\u8bd5\u63a5\u53e3\uff0c\u63a5\u53e3\u4e2d\u53ea\u6709\u4e00\u4e2a\u65b9\u6cd5\uff0c\u6253\u5370\u4f20\u5165\u7684\u5b57\u7b26\u4e32\u4fe1\u606f\u3002\u4ee3\u7801\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">package io.binghe.spi.service;\n\n\/**\n * @author binghe\n * @version 1.0.0\n * @description \u5b9a\u4e49\u63a5\u53e3\n *\/\npublic interface MyService {\n\n    \/**\n     *  \u6253\u5370\u4fe1\u606f\n     *\/\n    void print(String info);\n}<\/code><\/pre>\n<h3>5.\u521b\u5efa\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b<\/h3>\n<h4>\uff081\uff09\u521b\u5efa\u7b2c\u4e00\u4e2a\u5b9e\u73b0\u7c7bMyServiceA<\/h4>\n<p>\u5728io.binghe.spi.service.impl\u5305\u4e0b\u521b\u5efaMyServiceA\u7c7b\uff0c\u5b9e\u73b0MyService\u63a5\u53e3\u3002\u4ee3\u7801\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">package io.binghe.spi.service.impl;\nimport io.binghe.spi.service.MyService;\n\n\/**\n * @author binghe\n * @version 1.0.0\n * @description \u63a5\u53e3\u7684\u7b2c\u4e00\u4e2a\u5b9e\u73b0\n *\/\npublic class MyServiceA implements MyService {\n    @Override\n    public void print(String info) {\n        System.out.println(MyServiceA.class.getName() + &quot; print &quot; + info);\n    }\n}<\/code><\/pre>\n<h4>\uff082\uff09\u521b\u5efa\u7b2c\u4e8c\u4e2a\u5b9e\u73b0\u7c7bMyServiceB<\/h4>\n<p>\u5728io.binghe.spi.service.impl\u5305\u4e0b\u521b\u5efaMyServiceB\u7c7b\uff0c\u5b9e\u73b0MyService\u63a5\u53e3\u3002\u4ee3\u7801\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">package io.binghe.spi.service.impl;\n\nimport io.binghe.spi.service.MyService;\n\n\/**\n * @author binghe\n * @version 1.0.0\n * @description \u63a5\u53e3\u7b2c\u4e8c\u4e2a\u5b9e\u73b0\n *\/\npublic class MyServiceB implements MyService {\n    @Override\n    public void print(String info) {\n        System.out.println(MyServiceB.class.getName() + &quot; print &quot; + info);\n    }\n}<\/code><\/pre>\n<h4>6.\u521b\u5efa\u63a5\u53e3\u6587\u4ef6<\/h4>\n<p>\u5728\u9879\u76ee\u7684src\/main\/resources\u76ee\u5f55\u4e0b\u521b\u5efa<strong>META\/Services\/<\/strong>\u76ee\u5f55\uff0c\u5728\u76ee\u5f55\u4e2d\u521b\u5efaio.binghe.spi.service.MyService\u6587\u4ef6\uff0c\u6ce8\u610f\uff1a\u6587\u4ef6\u5fc5\u987b\u662f\u63a5\u53e3MyService\u7684\u5168\u540d\uff0c\u4e4b\u540e\u5c06\u5b9e\u73b0MyService\u63a5\u53e3\u7684\u7c7b\u914d\u7f6e\u5230\u6587\u4ef6\u4e2d\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"bash\">io.binghe.spi.service.impl.MyServiceA\nio.binghe.spi.service.impl.MyServiceB<\/code><\/pre>\n<h4>7.\u521b\u5efa\u6d4b\u8bd5\u7c7b<\/h4>\n<p>\u5728\u9879\u76ee\u7684io.binghe.spi.main\u5305\u4e0b\u521b\u5efaMain\u7c7b\uff0c\u8be5\u7c7b\u4e3a\u6d4b\u8bd5\u7a0b\u5e8f\u7684\u5165\u53e3\u7c7b\uff0c\u63d0\u4f9b\u4e00\u4e2amain()\u65b9\u6cd5\uff0c\u5728main()\u65b9\u6cd5\u4e2d\u8c03\u7528ServiceLoader\u7c7b\u52a0\u8f7dMyService\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u3002\u5e76\u901a\u8fc7Java8\u7684Stream\u5c06\u7ed3\u679c\u6253\u5370\u51fa\u6765\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">package io.binghe.spi.main;\n\nimport io.binghe.spi.loader.MyServiceLoader;\nimport io.binghe.spi.service.MyService;\n\nimport java.util.ServiceLoader;\nimport java.util.stream.StreamSupport;\n\n\/**\n * @author binghe\n * @version 1.0.0\n * @description \u6d4b\u8bd5\u7684main\u65b9\u6cd5\n *\/\npublic class Main {\n\n    public static void main(String[] args){\n        ServiceLoader&lt;MyService&gt; loader = MyServiceLoader.loadAll(MyService.class);\n        StreamSupport.stream(loader.spliterator(), false).forEach(s -&gt; s.print(&quot;Hello World&quot;));\n    }\n}<\/code><\/pre>\n<h4>8.\u6d4b\u8bd5\u5b9e\u4f8b<\/h4>\n<p>\u8fd0\u884cMain\u7c7b\u4e2d\u7684main()\u65b9\u6cd5\uff0c\u6253\u5370\u51fa\u7684\u4fe1\u606f\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"bash\">io.binghe.spi.service.impl.MyServiceA print Hello World\nio.binghe.spi.service.impl.MyServiceB print Hello World\n\nProcess finished with exit code 0<\/code><\/pre>\n<p>\u901a\u8fc7\u6253\u5370\u4fe1\u606f\u53ef\u4ee5\u770b\u51fa\uff0c\u901a\u8fc7Java SPI\u673a\u5236\u6b63\u786e\u52a0\u8f7d\u51fa\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\uff0c\u5e76\u8c03\u7528\u63a5\u53e3\u7684\u5b9e\u73b0\u65b9\u6cd5\u3002<\/p>\n<h2>\u6e90\u7801\u89e3\u6790<\/h2>\n<p>\u8fd9\u91cc\uff0c\u4e3b\u8981\u662f\u5bf9SPI\u7684\u52a0\u8f7d\u6d41\u7a0b\u6d89\u53ca\u5230\u7684<strong>java.util.ServiceLoader<\/strong>\u7684\u6e90\u7801\u7684\u89e3\u6790\u3002<\/p>\n<p>\u8fdb\u5165<strong>java.util.ServiceLoader<\/strong>\u7684\u6e90\u7801\uff0c\u53ef\u4ee5\u770b\u5230ServiceLoader\u7c7b\u5b9e\u73b0\u4e86<strong>java.lang.Iterable<\/strong>\u63a5\u53e3\uff0c\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<pre><code class=\"java\">public final class ServiceLoader&lt;S&gt;  implements Iterable&lt;S&gt; <\/code><\/pre>\n<p>\u8bf4\u660eServiceLoader\u7c7b\u662f\u53ef\u4ee5\u904d\u5386\u8fed\u4ee3\u7684\u3002<\/p>\n<p><strong>java.util.ServiceLoader<\/strong>\u7c7b\u4e2d\u5b9a\u4e49\u4e86\u5982\u4e0b\u7684\u6210\u5458\u53d8\u91cf\uff1a<\/p>\n<pre><code class=\"java\">\/\/ \u52a0\u8f7d\u5177\u4f53\u5b9e\u73b0\u7c7b\u4fe1\u606f\u7684\u524d\u7f00\uff0c\u4e5f\u5c31\u662f\u4ee5\u63a5\u53e3\u547d\u540d\u7684\u6587\u4ef6\u9700\u8981\u653e\u5230Jar\u5305\u4e2d\u7684META-INF\/services\/\u76ee\u5f55\u4e0b\nprivate static final String PREFIX = &quot;META-INF\/services\/&quot;;\n\n\/\/ \u9700\u8981\u52a0\u8f7d\u7684\u63a5\u53e3\nprivate final Class&lt;S&gt; service;\n\n\/\/ \u7c7b\u52a0\u8f7d\u5668\uff0c\u7528\u4e8e\u52a0\u8f7d\u4ee5\u63a5\u53e3\u547d\u540d\u7684\u6587\u4ef6\u4e2d\u914d\u7f6e\u7684\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\nprivate final ClassLoader loader;\n\n\/\/ \u521b\u5efaServiceLoader\u65f6\u91c7\u7528\u7684\u8bbf\u95ee\u63a7\u5236\u4e0a\u4e0b\u6587\u73af\u5883\nprivate final AccessControlContext acc;\n\n\/\/ \u7528\u6765\u7f13\u5b58\u5df2\u7ecf\u52a0\u8f7d\u7684\u63a5\u53e3\u5b9e\u73b0\u7c7b\uff0c\u5176\u4e2d\uff0cKey\u662f\u63a5\u53e3\u5b9e\u73b0\u7c7b\u7684\u5b8c\u6574\u7c7b\u540d\uff0cValue\u4e3a\u5b9e\u73b0\u7c7b\u5bf9\u8c61\nprivate LinkedHashMap&lt;String,S&gt; providers = new LinkedHashMap&lt;&gt;();\n\n\/\/ \u7528\u4e8e\u5ef6\u8fdf\u52a0\u8f7d\u5b9e\u73b0\u7c7b\u7684\u8fed\u4ee3\u5668\nprivate LazyIterator lookupIterator;<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u5230ServiceLoader\u7c7b\u4e2d\u5b9a\u4e49\u4e86\u52a0\u8f7d\u524d\u7f00\u4e3a\u201cMETA-INF\/services\/\u201d\uff0c\u6240\u4ee5\uff0c\u63a5\u53e3\u6587\u4ef6\u5fc5\u987b\u8981\u5728\u9879\u76ee\u7684<strong>src\/main\/resources<\/strong>\u76ee\u5f55\u4e0b\u7684<strong>META-INF\/services\/<\/strong>\u76ee\u5f55\u4e0b\u521b\u5efa\u3002<\/p>\n<p>\u4eceMyServiceLoader\u7c7b\u8c03\u7528<strong>ServiceLoader.load(clazz)<\/strong>\u65b9\u6cd5\u8fdb\u5165\u6e90\u7801\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">\/\/\u6839\u636e\u7c7b\u7684Class\u5bf9\u8c61\u52a0\u8f7d\u6307\u5b9a\u7684\u7c7b\uff0c\u8fd4\u56deServiceLoader\u5bf9\u8c61\npublic static &lt;S&gt; ServiceLoader&lt;S&gt; load(Class&lt;S&gt; service) {\n    \/\/\u83b7\u53d6\u5f53\u524d\u7ebf\u7a0b\u7684\u7c7b\u52a0\u8f7d\u5668\n    ClassLoader cl = Thread.currentThread().getContextClassLoader();\n    \/\/\u52a8\u6001\u52a0\u8f7d\u6307\u5b9a\u7684\u7c7b\uff0c\u5c06\u7c7b\u52a0\u8f7d\u5230ServiceLoader\u4e2d\n    return ServiceLoader.load(service, cl);\n}<\/code><\/pre>\n<p>\u65b9\u6cd5\u4e2d\u8c03\u7528\u4e86<strong>ServiceLoader.load(service, cl)<\/strong>\u65b9\u6cd5\uff0c\u7ee7\u7eed\u8ddf\u8e2a\u4ee3\u7801\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">\/\/\u901a\u8fc7ClassLoader\u52a0\u8f7d\u6307\u5b9a\u7c7b\u7684Class\uff0c\u5e76\u5c06\u8fd4\u56de\u7ed3\u679c\u5c01\u88c5\u5230ServiceLoader\u5bf9\u8c61\u4e2d\npublic static &lt;S&gt; ServiceLoader&lt;S&gt; load(Class&lt;S&gt; service, ClassLoader loader){\n    return new ServiceLoader&lt;&gt;(service, loader);\n}<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u5230<strong>ServiceLoader.load(service, cl)<\/strong>\u65b9\u6cd5\u4e2d\uff0c\u8c03\u7528\u4e86ServiceLoader\u7c7b\u7684\u6784\u9020\u65b9\u6cd5\uff0c\u7ee7\u7eed\u8ddf\u8fdb\u4ee3\u7801\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">\/\/\u6784\u9020ServiceLoader\u5bf9\u8c61\nprivate ServiceLoader(Class&lt;S&gt; svc, ClassLoader cl) {\n    \/\/\u5982\u679c\u4f20\u5165\u7684Class\u5bf9\u8c61\u4e3a\u7a7a\uff0c\u5219\u5224\u5904\u7a7a\u6307\u9488\u5f02\u5e38\n    service = Objects.requireNonNull(svc, &quot;Service interface cannot be null&quot;);\n    \/\/\u5982\u679c\u4f20\u5165\u7684ClassLoader\u4e3a\u7a7a\uff0c\u5219\u901a\u8fc7ClassLoader.getSystemClassLoader()\u83b7\u53d6\uff0c\u5426\u5219\u76f4\u63a5\u4f7f\u7528\u4f20\u5165\u7684ClassLoader\n    loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;\n    acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;\n    reload();\n}<\/code><\/pre>\n<p>\u7ee7\u7eed\u8ddf<strong>reload()<\/strong>\u65b9\u6cd5\uff0c\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<pre><code class=\"java\">\/\/\u91cd\u65b0\u52a0\u8f7d\npublic void reload() {\n    \/\/\u6e05\u7a7a\u4fdd\u5b58\u52a0\u8f7d\u7684\u5b9e\u73b0\u7c7b\u7684LinkedHashMap\n    providers.clear();\n    \/\/\u6784\u9020\u5ef6\u8fdf\u52a0\u8f7d\u7684\u8fed\u4ee3\u5668\n    lookupIterator = new LazyIterator(service, loader);\n}<\/code><\/pre>\n<p>\u7ee7\u7eed\u8ddf\u8fdb\u61d2\u52a0\u8f7d\u8fed\u4ee3\u5668\u7684\u6784\u9020\u51fd\u6570\uff0c\u5982\u4e0b\u6240\u793a\u3002<\/p>\n<pre><code class=\"java\">private LazyIterator(Class&lt;S&gt; service, ClassLoader loader) {\n    this.service = service;\n    this.loader = loader;\n}<\/code><\/pre>\n<p>\u53ef\u4ee5\u770b\u5230\uff0c\u4f1a\u5c06\u9700\u8981\u52a0\u8f7d\u7684\u63a5\u53e3\u7684Class\u5bf9\u8c61\u548c\u7c7b\u52a0\u8f7d\u5668\u8d4b\u503c\u7ed9<strong>LazyIterator<\/strong>\u7684\u6210\u5458\u53d8\u91cf\u3002<\/p>\n<p>\u5f53\u6211\u4eec\u5728\u7a0b\u5e8f\u4e2d\u8fed\u4ee3\u83b7\u53d6\u5bf9\u8c61\u5b9e\u4f8b\u65f6\uff0c\u9996\u5148\u5728\u6210\u5458\u53d8\u91cf<strong><code>providers<\/code><\/strong>\u4e2d\u67e5\u627e\u662f\u5426\u6709\u7f13\u5b58\u7684\u5b9e\u4f8b\u5bf9\u8c61\u3002\u5982\u679c\u5b58\u5728\u5219\u76f4\u63a5\u8fd4\u56de\uff0c\u5426\u5219\u8c03\u7528<strong><code>lookupIterator<\/code><\/strong>\u5ef6\u8fdf\u52a0\u8f7d\u8fed\u4ee3\u5668\u8fdb\u884c\u52a0\u8f7d\u3002<\/p>\n<p>\u8fed\u4ee3\u5668\u8fdb\u884c\u903b\u8f91\u5224\u65ad\u7684\u4ee3\u7801\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">\/\/\u8fed\u4ee3ServiceLoader\u7684\u65b9\u6cd5\npublic Iterator&lt;S&gt; iterator() {\n    return new Iterator&lt;S&gt;() {\n        \/\/\u83b7\u53d6\u4fdd\u5b58\u5b9e\u73b0\u7c7b\u7684LinkedHashMap&lt;String,S&gt;\u7684\u8fed\u4ee3\u5668\n        Iterator&lt;Map.Entry&lt;String,S&gt;&gt; knownProviders = providers.entrySet().iterator();\n        \/\/\u5224\u65ad\u662f\u5426\u6709\u4e0b\u4e00\u4e2a\u5143\u7d20\n        public boolean hasNext() {\n            \/\/\u5982\u679cknownProviders\u5b58\u5728\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u8fd4\u56detrue\n            if (knownProviders.hasNext())\n                return true;\n            \/\/\u8fd4\u56de\u5ef6\u8fdf\u52a0\u8f7d\u5668\u662f\u5426\u5b58\u5728\u5143\u7d20\n            return lookupIterator.hasNext();\n        }\n        \/\/\u83b7\u53d6\u4e0b\u4e00\u4e2a\u5143\u7d20\n        public S next() {\n            \/\/\u5982\u679cknownProviders\u5b58\u5728\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u83b7\u53d6\n            if (knownProviders.hasNext())\n                return knownProviders.next().getValue();\n            \/\/\u83b7\u53d6\u5ef6\u8fdf\u8fed\u4ee3\u5668lookupIterator\u4e2d\u7684\u5143\u7d20\n            return lookupIterator.next();\n        }\n\n        public void remove() {\n            throw new UnsupportedOperationException();\n        }\n\n    };\n}<\/code><\/pre>\n<p><strong>LazyIterator<\/strong>\u52a0\u8f7d\u7c7b\u7684\u6d41\u7a0b\u5982\u4e0b\u4ee3\u7801\u6240\u793a<\/p>\n<pre><code class=\"java\">\/\/\u5224\u65ad\u662f\u5426\u62e5\u6709\u4e0b\u4e00\u4e2a\u5b9e\u4f8b\nprivate boolean hasNextService() {\n    \/\/\u5982\u679c\u62e5\u6709\u4e0b\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u76f4\u63a5\u8fd4\u56detrue\n    if (nextName != null) {\n        return true;\n    }\n    \/\/\u5982\u679c\u5b9e\u73b0\u7c7b\u7684\u5168\u540d\u4e3anull\n    if (configs == null) {\n        try {\n            \/\/\u83b7\u53d6\u5168\u6587\u4ef6\u540d\uff0c\u6587\u4ef6\u76f8\u5bf9\u8def\u5f84+\u6587\u4ef6\u540d\u79f0\uff08\u5305\u540d+\u63a5\u53e3\u540d\uff09\n            String fullName = PREFIX + service.getName();\n            \/\/\u7c7b\u52a0\u8f7d\u5668\u4e3a\u7a7a\uff0c\u5219\u901a\u8fc7ClassLoader.getSystemResources()\u65b9\u6cd5\u83b7\u53d6\n            if (loader == null)\n                configs = ClassLoader.getSystemResources(fullName);\n            else\n                \/\/\u7c7b\u52a0\u8f7d\u5668\u4e0d\u4e3a\u7a7a\uff0c\u5219\u76f4\u63a5\u901a\u8fc7\u7c7b\u52a0\u8f7d\u5668\u83b7\u53d6\n                configs = loader.getResources(fullName);\n        } catch (IOException x) {\n            fail(service, &quot;Error locating configuration files&quot;, x);\n        }\n    }\n    while ((pending == null) || !pending.hasNext()) {\n        \/\/\u5982\u679cconfigs\u4e2d\u6ca1\u6709\u66f4\u8fc7\u7684\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u8fd4\u56defalse\n        if (!configs.hasMoreElements()) {\n            return false;\n        }\n        \/\/\u89e3\u6790\u5305\u7ed3\u6784\n        pending = parse(service, configs.nextElement());\n    }\n    nextName = pending.next();\n    return true;\n}\n\nprivate S nextService() {\n    if (!hasNextService())\n        throw new NoSuchElementException();\n    String cn = nextName;\n    nextName = null;\n    Class&lt;?&gt; c = null;\n    try {\n        \/\/\u52a0\u8f7d\u7c7b\u5bf9\u8c61\n        c = Class.forName(cn, false, loader);\n    } catch (ClassNotFoundException x) {\n        fail(service,\n             &quot;Provider &quot; + cn + &quot; not found&quot;);\n    }\n    if (!service.isAssignableFrom(c)) {\n        fail(service,\n             &quot;Provider &quot; + cn  + &quot; not a subtype&quot;);\n    }\n    try {\n        \/\/\u901a\u8fc7c.newInstance()\u751f\u6210\u5bf9\u8c61\u5b9e\u4f8b\n        S p = service.cast(c.newInstance());\n        \/\/\u5c06\u751f\u6210\u7684\u5bf9\u8c61\u5b9e\u4f8b\u4fdd\u5b58\u5230\u7f13\u5b58\u4e2d\uff08LinkedHashMap&lt;String,S&gt;\uff09\n        providers.put(cn, p);\n        return p;\n    } catch (Throwable x) {\n        fail(service,\n             &quot;Provider &quot; + cn + &quot; could not be instantiated&quot;,\n             x);\n    }\n    throw new Error();          \/\/ This cannot happen\n}\n\npublic boolean hasNext() {\n    if (acc == null) {\n        return hasNextService();\n    } else {\n        PrivilegedAction&lt;Boolean&gt; action = new PrivilegedAction&lt;Boolean&gt;() {\n            public Boolean run() { return hasNextService(); }\n        };\n        return AccessController.doPrivileged(action, acc);\n    }\n}\n\npublic S next() {\n    if (acc == null) {\n        return nextService();\n    } else {\n        PrivilegedAction&lt;S&gt; action = new PrivilegedAction&lt;S&gt;() {\n            public S run() { return nextService(); }\n        };\n        return AccessController.doPrivileged(action, acc);\n    }\n}<\/code><\/pre>\n<p>\u6700\u540e\uff0c\u7ed9\u51fa\u6574\u4e2a<strong>java.util.ServiceLoader<\/strong>\u7684\u7c7b\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code class=\"java\">package java.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.security.AccessControlContext;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\n\n\npublic final class ServiceLoader&lt;S&gt;  implements Iterable&lt;S&gt; {\n    \/\/ \u52a0\u8f7d\u5177\u4f53\u5b9e\u73b0\u7c7b\u4fe1\u606f\u7684\u524d\u7f00\uff0c\u4e5f\u5c31\u662f\u4ee5\u63a5\u53e3\u547d\u540d\u7684\u6587\u4ef6\u9700\u8981\u653e\u5230Jar\u5305\u4e2d\u7684META-INF\/services\/\u76ee\u5f55\u4e0b\n    private static final String PREFIX = &quot;META-INF\/services\/&quot;;\n\n    \/\/ \u9700\u8981\u52a0\u8f7d\u7684\u63a5\u53e3\n    private final Class&lt;S&gt; service;\n\n    \/\/ \u7c7b\u52a0\u8f7d\u5668\uff0c\u7528\u4e8e\u52a0\u8f7d\u4ee5\u63a5\u53e3\u547d\u540d\u7684\u6587\u4ef6\u4e2d\u914d\u7f6e\u7684\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\n    private final ClassLoader loader;\n\n    \/\/ \u521b\u5efaServiceLoader\u65f6\u91c7\u7528\u7684\u8bbf\u95ee\u63a7\u5236\u4e0a\u4e0b\u6587\u73af\u5883\n    private final AccessControlContext acc;\n\n    \/\/ \u7528\u6765\u7f13\u5b58\u5df2\u7ecf\u52a0\u8f7d\u7684\u63a5\u53e3\u5b9e\u73b0\u7c7b\uff0c\u5176\u4e2d\uff0cKey\u662f\u63a5\u53e3\u5b9e\u73b0\u7c7b\u7684\u5b8c\u6574\u7c7b\u540d\uff0cValue\u4e3a\u5b9e\u73b0\u7c7b\u5bf9\u8c61\n    private LinkedHashMap&lt;String,S&gt; providers = new LinkedHashMap&lt;&gt;();\n\n    \/\/ \u7528\u4e8e\u5ef6\u8fdf\u52a0\u8f7d\u5b9e\u73b0\u7c7b\u7684\u8fed\u4ee3\u5668\n    private LazyIterator lookupIterator;\n\n    \/\/\u91cd\u65b0\u52a0\u8f7d\n    public void reload() {\n        \/\/\u6e05\u7a7a\u4fdd\u5b58\u52a0\u8f7d\u7684\u5b9e\u73b0\u7c7b\u7684LinkedHashMap\n        providers.clear();\n        \/\/\u6784\u9020\u5ef6\u8fdf\u52a0\u8f7d\u7684\u8fed\u4ee3\u5668\n        lookupIterator = new LazyIterator(service, loader);\n    }\n\n    \/\/\u6784\u9020ServiceLoader\u5bf9\u8c61\n    private ServiceLoader(Class&lt;S&gt; svc, ClassLoader cl) {\n        \/\/\u5982\u679c\u4f20\u5165\u7684Class\u5bf9\u8c61\u4e3a\u7a7a\uff0c\u5219\u5224\u5904\u7a7a\u6307\u9488\u5f02\u5e38\n        service = Objects.requireNonNull(svc, &quot;Service interface cannot be null&quot;);\n        \/\/\u5982\u679c\u4f20\u5165\u7684ClassLoader\u4e3a\u7a7a\uff0c\u5219\u901a\u8fc7ClassLoader.getSystemClassLoader()\u83b7\u53d6\uff0c\u5426\u5219\u76f4\u63a5\u4f7f\u7528\u4f20\u5165\u7684ClassLoader\n        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;\n        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;\n        reload();\n    }\n\n    private static void fail(Class&lt;?&gt; service, String msg, Throwable cause)\n        throws ServiceConfigurationError\n    {\n        throw new ServiceConfigurationError(service.getName() + &quot;: &quot; + msg,\n                                            cause);\n    }\n\n    private static void fail(Class&lt;?&gt; service, String msg)\n        throws ServiceConfigurationError\n    {\n        throw new ServiceConfigurationError(service.getName() + &quot;: &quot; + msg);\n    }\n\n    private static void fail(Class&lt;?&gt; service, URL u, int line, String msg)\n        throws ServiceConfigurationError\n    {\n        fail(service, u + &quot;:&quot; + line + &quot;: &quot; + msg);\n    }\n\n    \/\/ Parse a single line from the given configuration file, adding the name\n    \/\/ on the line to the names list.\n    \/\/\n    private int parseLine(Class&lt;?&gt; service, URL u, BufferedReader r, int lc,\n                          List&lt;String&gt; names)\n        throws IOException, ServiceConfigurationError\n    {\n        String ln = r.readLine();\n        if (ln == null) {\n            return -1;\n        }\n        int ci = ln.indexOf('#');\n        if (ci &gt;= 0) ln = ln.substring(0, ci);\n        ln = ln.trim();\n        int n = ln.length();\n        if (n != 0) {\n            if ((ln.indexOf(' ') &gt;= 0) || (ln.indexOf('\/t') &gt;= 0))\n                fail(service, u, lc, &quot;Illegal configuration-file syntax&quot;);\n            int cp = ln.codePointAt(0);\n            if (!Character.isJavaIdentifierStart(cp))\n                fail(service, u, lc, &quot;Illegal provider-class name: &quot; + ln);\n            for (int i = Character.charCount(cp); i &lt; n; i += Character.charCount(cp)) {\n                cp = ln.codePointAt(i);\n                if (!Character.isJavaIdentifierPart(cp) &amp;&amp; (cp != '.'))\n                    fail(service, u, lc, &quot;Illegal provider-class name: &quot; + ln);\n            }\n            if (!providers.containsKey(ln) &amp;&amp; !names.contains(ln))\n                names.add(ln);\n        }\n        return lc + 1;\n    }\n\n    private Iterator&lt;String&gt; parse(Class&lt;?&gt; service, URL u)\n        throws ServiceConfigurationError\n    {\n        InputStream in = null;\n        BufferedReader r = null;\n        ArrayList&lt;String&gt; names = new ArrayList&lt;&gt;();\n        try {\n            in = u.openStream();\n            r = new BufferedReader(new InputStreamReader(in, &quot;utf-8&quot;));\n            int lc = 1;\n            while ((lc = parseLine(service, u, r, lc, names)) &gt;= 0);\n        } catch (IOException x) {\n            fail(service, &quot;Error reading configuration file&quot;, x);\n        } finally {\n            try {\n                if (r != null) r.close();\n                if (in != null) in.close();\n            } catch (IOException y) {\n                fail(service, &quot;Error closing configuration file&quot;, y);\n            }\n        }\n        return names.iterator();\n    }\n\n    \/\/ Private inner class implementing fully-lazy provider lookupload\n    private class LazyIterator\n        implements Iterator&lt;S&gt;\n    {\n\n        Class&lt;S&gt; service;\n        ClassLoader loader;\n        Enumeration&lt;URL&gt; configs = null;\n        Iterator&lt;String&gt; pending = null;\n        String nextName = null;\n\n        private LazyIterator(Class&lt;S&gt; service, ClassLoader loader) {\n            this.service = service;\n            this.loader = loader;\n        }\n\n        \/\/\u5224\u65ad\u662f\u5426\u62e5\u6709\u4e0b\u4e00\u4e2a\u5b9e\u4f8b\n        private boolean hasNextService() {\n            \/\/\u5982\u679c\u62e5\u6709\u4e0b\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u76f4\u63a5\u8fd4\u56detrue\n            if (nextName != null) {\n                return true;\n            }\n            \/\/\u5982\u679c\u5b9e\u73b0\u7c7b\u7684\u5168\u540d\u4e3anull\n            if (configs == null) {\n                try {\n                    \/\/\u83b7\u53d6\u5168\u6587\u4ef6\u540d\uff0c\u6587\u4ef6\u76f8\u5bf9\u8def\u5f84+\u6587\u4ef6\u540d\u79f0\uff08\u5305\u540d+\u63a5\u53e3\u540d\uff09\n                    String fullName = PREFIX + service.getName();\n                    \/\/\u7c7b\u52a0\u8f7d\u5668\u4e3a\u7a7a\uff0c\u5219\u901a\u8fc7ClassLoader.getSystemResources()\u65b9\u6cd5\u83b7\u53d6\n                    if (loader == null)\n                        configs = ClassLoader.getSystemResources(fullName);\n                    else\n                        \/\/\u7c7b\u52a0\u8f7d\u5668\u4e0d\u4e3a\u7a7a\uff0c\u5219\u76f4\u63a5\u901a\u8fc7\u7c7b\u52a0\u8f7d\u5668\u83b7\u53d6\n                        configs = loader.getResources(fullName);\n                } catch (IOException x) {\n                    fail(service, &quot;Error locating configuration files&quot;, x);\n                }\n            }\n            while ((pending == null) || !pending.hasNext()) {\n                \/\/\u5982\u679cconfigs\u4e2d\u6ca1\u6709\u66f4\u8fc7\u7684\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u8fd4\u56defalse\n                if (!configs.hasMoreElements()) {\n                    return false;\n                }\n                \/\/\u89e3\u6790\u5305\u7ed3\u6784\n                pending = parse(service, configs.nextElement());\n            }\n            nextName = pending.next();\n            return true;\n        }\n\n        private S nextService() {\n            if (!hasNextService())\n                throw new NoSuchElementException();\n            String cn = nextName;\n            nextName = null;\n            Class&lt;?&gt; c = null;\n            try {\n                \/\/\u52a0\u8f7d\u7c7b\u5bf9\u8c61\n                c = Class.forName(cn, false, loader);\n            } catch (ClassNotFoundException x) {\n                fail(service,\n                     &quot;Provider &quot; + cn + &quot; not found&quot;);\n            }\n            if (!service.isAssignableFrom(c)) {\n                fail(service,\n                     &quot;Provider &quot; + cn  + &quot; not a subtype&quot;);\n            }\n            try {\n                \/\/\u901a\u8fc7c.newInstance()\u751f\u6210\u5bf9\u8c61\u5b9e\u4f8b\n                S p = service.cast(c.newInstance());\n                \/\/\u5c06\u751f\u6210\u7684\u5bf9\u8c61\u5b9e\u4f8b\u4fdd\u5b58\u5230\u7f13\u5b58\u4e2d\uff08LinkedHashMap&lt;String,S&gt;\uff09\n                providers.put(cn, p);\n                return p;\n            } catch (Throwable x) {\n                fail(service,\n                     &quot;Provider &quot; + cn + &quot; could not be instantiated&quot;,\n                     x);\n            }\n            throw new Error();          \/\/ This cannot happen\n        }\n\n        public boolean hasNext() {\n            if (acc == null) {\n                return hasNextService();\n            } else {\n                PrivilegedAction&lt;Boolean&gt; action = new PrivilegedAction&lt;Boolean&gt;() {\n                    public Boolean run() { return hasNextService(); }\n                };\n                return AccessController.doPrivileged(action, acc);\n            }\n        }\n\n        public S next() {\n            if (acc == null) {\n                return nextService();\n            } else {\n                PrivilegedAction&lt;S&gt; action = new PrivilegedAction&lt;S&gt;() {\n                    public S run() { return nextService(); }\n                };\n                return AccessController.doPrivileged(action, acc);\n            }\n        }\n\n        public void remove() {\n            throw new UnsupportedOperationException();\n        }\n\n    }\n\n    \/\/\u8fed\u4ee3ServiceLoader\u7684\u65b9\u6cd5\n    public Iterator&lt;S&gt; iterator() {\n        return new Iterator&lt;S&gt;() {\n            \/\/\u83b7\u53d6\u4fdd\u5b58\u5b9e\u73b0\u7c7b\u7684LinkedHashMap&lt;String,S&gt;\u7684\u8fed\u4ee3\u5668\n            Iterator&lt;Map.Entry&lt;String,S&gt;&gt; knownProviders = providers.entrySet().iterator();\n            \/\/\u5224\u65ad\u662f\u5426\u6709\u4e0b\u4e00\u4e2a\u5143\u7d20\n            public boolean hasNext() {\n                \/\/\u5982\u679cknownProviders\u5b58\u5728\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u8fd4\u56detrue\n                if (knownProviders.hasNext())\n                    return true;\n                \/\/\u8fd4\u56de\u5ef6\u8fdf\u52a0\u8f7d\u5668\u662f\u5426\u5b58\u5728\u5143\u7d20\n                return lookupIterator.hasNext();\n            }\n            \/\/\u83b7\u53d6\u4e0b\u4e00\u4e2a\u5143\u7d20\n            public S next() {\n                \/\/\u5982\u679cknownProviders\u5b58\u5728\u5143\u7d20\uff0c\u5219\u76f4\u63a5\u83b7\u53d6\n                if (knownProviders.hasNext())\n                    return knownProviders.next().getValue();\n                \/\/\u83b7\u53d6\u5ef6\u8fdf\u8fed\u4ee3\u5668lookupIterator\u4e2d\u7684\u5143\u7d20\n                return lookupIterator.next();\n            }\n\n            public void remove() {\n                throw new UnsupportedOperationException();\n            }\n\n        };\n    }\n\n    \/\/\u901a\u8fc7ClassLoader\u52a0\u8f7d\u6307\u5b9a\u7c7b\u7684Class\uff0c\u5e76\u5c06\u8fd4\u56de\u7ed3\u679c\u5c01\u88c5\u5230ServiceLoader\u5bf9\u8c61\u4e2d\n    public static &lt;S&gt; ServiceLoader&lt;S&gt; load(Class&lt;S&gt; service,\n                                            ClassLoader loader)\n    {\n        return new ServiceLoader&lt;&gt;(service, loader);\n    }\n\n    \/\/\u6839\u636e\u7c7b\u7684Class\u5bf9\u8c61\u52a0\u8f7d\u6307\u5b9a\u7684\u7c7b\uff0c\u8fd4\u56deServiceLoader\u5bf9\u8c61\n    public static &lt;S&gt; ServiceLoader&lt;S&gt; load(Class&lt;S&gt; service) {\n        \/\/\u83b7\u53d6\u5f53\u524d\u7ebf\u7a0b\u7684\u7c7b\u52a0\u8f7d\u5668\n        ClassLoader cl = Thread.currentThread().getContextClassLoader();\n        \/\/\u52a8\u6001\u52a0\u8f7d\u6307\u5b9a\u7684\u7c7b\uff0c\u5c06\u7c7b\u52a0\u8f7d\u5230ServiceLoader\u4e2d\n        return ServiceLoader.load(service, cl);\n    }\n    \n    public static &lt;S&gt; ServiceLoader&lt;S&gt; loadInstalled(Class&lt;S&gt; service) {\n        ClassLoader cl = ClassLoader.getSystemClassLoader();\n        ClassLoader prev = null;\n        while (cl != null) {\n            prev = cl;\n            cl = cl.getParent();\n        }\n        return ServiceLoader.load(service, prev);\n    }\n\n    \/**\n     * Returns a string describing this service.\n     *\n     * @return  A descriptive string\n     *\/\n    public String toString() {\n        return &quot;java.util.ServiceLoader[&quot; + service.getName() + &quot;]&quot;;\n    }\n\n}<\/code><\/pre>\n<h2>SPI\u603b\u7ed3<\/h2>\n<p>\u6700\u540e\uff0c\u5bf9Java\u63d0\u4f9b\u7684SPI\u673a\u5236\u8fdb\u884c\u7b80\u5355\u7684\u603b\u7ed3\u3002<\/p>\n<h3>\u4f18\u70b9\uff1a<\/h3>\n<p>\u80fd\u591f\u5b9e\u73b0\u9879\u76ee\u89e3\u8026\uff0c\u4f7f\u5f97\u7b2c\u4e09\u65b9\u670d\u52a1\u6a21\u5757\u7684\u88c5\u914d\u63a7\u5236\u7684\u903b\u8f91\u4e0e\u8c03\u7528\u8005\u7684\u4e1a\u52a1\u4ee3\u7801\u5206\u79bb\uff0c\u800c\u4e0d\u662f\u8026\u5408\u5728\u4e00\u8d77\u3002\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u4e1a\u52a1\u60c5\u51b5\u542f\u7528\u6846\u67b6\u6269\u5c55\u6216\u66ff\u6362\u6846\u67b6\u7ec4\u4ef6\u3002<\/p>\n<h3>\u7f3a\u70b9\uff1a<\/h3>\n<ul>\n<li>\u591a\u4e2a\u5e76\u53d1\u591a\u7ebf\u7a0b\u4f7f\u7528ServiceLoader\u7c7b\u7684\u5b9e\u4f8b\u662f\u4e0d\u5b89\u5168\u7684<\/li>\n<li>\u867d\u7136ServiceLoader\u4e5f\u7b97\u662f\u4f7f\u7528\u7684\u5ef6\u8fdf\u52a0\u8f7d\uff0c\u4f46\u662f\u57fa\u672c\u53ea\u80fd\u901a\u8fc7\u904d\u5386\u5168\u90e8\u83b7\u53d6\uff0c\u4e5f\u5c31\u662f\u63a5\u53e3\u7684\u5b9e\u73b0\u7c7b\u5168\u90e8\u52a0\u8f7d\u5e76\u5b9e\u4f8b\u5316\u4e00\u904d\u3002<\/li>\n<\/ul>\n<p>\u53c2\u8003\uff1a<a href=\"https:\/\/link.segmentfault.com\/?enc=X4sJ9DV2GfPS63Agj8Pfaw%3D%3D.2ULdaf1UJN5%2BTosbrHuSeLd6XWVg0a6cdfPkY3%2BmpicUNGD31ua8yG2rcoVaOTWv42y0mhWIf46BZlKJDg3fbQ%3D%3D\" rel=\"nofollow\">\u6df1\u5165\u7406\u89e3Java\u4e2d\u7684spi\u673a\u5236<\/a><\/p>\n<p><strong>\u597d\u4e86\uff0c\u4eca\u5929\u5c31\u5230\u8fd9\u513f\u5427\uff0c\u6211\u662f\u51b0\u6cb3\uff0c\u6211\u4eec\u4e0b\u671f\u89c1~~<\/strong><\/p>\n<p><a href=\"https:\/\/segmentfault.com\/a\/1190000042319253\">https:\/\/segmentfault.com\/a\/1190000042319253<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5927\u5bb6\u597d\uff0c\u6211\u662f\u51b0\u6cb3~~ SPI\u7684\u6982\u5ff5 JAVA SPI = \u57fa\u4e8e\u63a5\u53e3\u7684\u7f16\u7a0b\uff0b\u7b56\u7565\u6a21\u5f0f\uff0b\u914d\u7f6e\u6587\u4ef6 \u7684\u52a8\u6001\u52a0\u8f7d\u673a\u5236  [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[],"tags":[],"class_list":["post-10006201","post","type-post","status-publish","format-standard","hentry"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10006201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10006201"}],"version-history":[{"count":0,"href":"https:\/\/itmax.cn\/index.php?rest_route=\/wp\/v2\/posts\/10006201\/revisions"}],"wp:attachment":[{"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10006201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10006201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itmax.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10006201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}