-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathServiceLoaderDemo.java
More file actions
119 lines (106 loc) · 3.85 KB
/
Copy pathServiceLoaderDemo.java
File metadata and controls
119 lines (106 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package Phase9_ModernJavaAndModules.Modules;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* ServiceLoader — the Built-In Plugin / SPI Mechanism
* ---------------------------------------------------
* ServiceLoader lets you declare a SERVICE INTERFACE and DISCOVER
* implementations at runtime — without hard-coding their names.
* <p>
*
* Two pieces
* ----------
* 1. A service INTERFACE (or abstract class).
* 2. ONE or more implementations, declared so the JVM can find them.
* <p>
*
* Declaring providers
* -------------------
* <p>
*
* Classpath / unnamed module: a META-INF/services/<interface name>
* text file listing implementation classes, one per line:
* <p>
*
* META-INF/services/com.example.api.Codec
* -----------------------------------------
* com.example.codec.GzipCodec
* com.example.codec.SnappyCodec
* <p>
*
* Modular projects: declare in module-info.java instead:
* <p>
*
* module com.example.codec {
* requires com.example.api;
* provides com.example.api.Codec
* with com.example.codec.GzipCodec,
* com.example.codec.SnappyCodec;
* }
* <p>
*
* Loading at runtime
* ------------------
* ServiceLoader<Codec> loader = ServiceLoader.load(Codec.class);
* for (Codec c : loader) { ... }
* <p>
*
* loader.stream()
* .map(ServiceLoader.Provider::get)
* .filter(c -> c.canHandle(input))
* .findFirst();
* <p>
*
* Real-world examples
* -------------------
* - JDBC drivers (java.sql.Driver) — historic, before SPI
* formalisation but now uses it.
* - Logging (SLF4J, java.util.spi providers).
* - Java Sound, Cryptography Providers, Locale providers, Charsets.
* <p>
*
* Demo — this file
* ----------------
* Without a module-info.java OR a META-INF/services entry, our
* demo Codec interface has zero registered providers. The file walks
* through the API and lists JDK-provided SPIs that DO have providers
* (so we can show ServiceLoader actually finding things).
*/
public class ServiceLoaderDemo {
/** A toy SPI for the demo. */
public interface Codec {
String name();
byte[] encode(byte[] in);
}
public static void main(String[] args) {
section("1) Our toy SPI has zero providers (nothing registered)");
ServiceLoader<Codec> codecs = ServiceLoader.load(Codec.class);
Iterator<Codec> it = codecs.iterator();
if (!it.hasNext()) System.out.println(" no Codec providers found");
else codecs.forEach(c -> System.out.println(" " + c.name()));
section("2) JDK-provided SPI: java.sql.Driver (if drivers are on classpath)");
listProviders(java.sql.Driver.class);
section("3) JDK-provided SPI: java.nio.file.spi.FileSystemProvider");
listProviders(java.nio.file.spi.FileSystemProvider.class);
section("4) JDK-provided SPI: java.nio.charset.spi.CharsetProvider");
listProviders(java.nio.charset.spi.CharsetProvider.class);
section("5) Stream API — pick a provider lazily");
codecs.stream()
.map(ServiceLoader.Provider::type)
.forEach(c -> System.out.println(" candidate: " + c.getName()));
section("done — wire a real META-INF/services file to see providers appear");
}
private static <T> void listProviders(Class<T> spi) {
ServiceLoader<T> sl = ServiceLoader.load(spi);
int count = 0;
for (T provider : sl) {
System.out.println(" " + provider.getClass().getName());
count++;
}
if (count == 0) System.out.println(" (no providers registered for " + spi.getSimpleName() + ")");
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}