In the previous article: Java SPI (Service Provider Interface) introduced a brief description of the Java SPI mechanism, and attached a specific demo. Not familiar with the Java SPI students can go to see the article, this article no longer repeat.
This article will be based on the previous article, combined with JDK 1.7 source to analyze the Java SPI Internal implementation principle.
In the previous article, we obtained the specific implementation of the service through the following code:
Import Java.util.Iterator;
Import Java.util.ServiceLoader;
Import Com.ricky.codelab.spi.DemoService;
1.serviceloader.load
serviceloader<demoservice> serviceloader = serviceloader.load (DemoService.class) ;
2.serviceloader.iterator ()
iterator<demoservice> it = Serviceloader.iterator ();
3.hasNext () while
(It.hasnext ()) {
//4.next ()
demoservice demoservice = It.next ();
}
1, Serviceloader.load method
First look at the Serviceloader.load method, as follows:
public static <S> serviceloader<s> load (class<s> service) {
ClassLoader cl = Thread.CurrentThread (). Getcontextclassloader ();
return Serviceloader.load (service, CL);
}
It has an overloaded method, as follows:
public static <S> serviceloader<s> load (class<s> service,
ClassLoader loader) {return
new Serviceloader<> (service, loader);
This returns a Serviceloader instance object,serviceloader<> (service, loader) by calling new Serviceloader<> (service, loader) The construction method is as follows:
Private Serviceloader (Class<s> Svc, ClassLoader cl) {
service = svc;
loader = CL;
Reload ();
}
The reload method is called internally by the constructor method, as follows:
public void Reload () {
providers.clear ();
Lookupiterator = new Lazyiterator (service, loader);
}
The providers, Lookupiterator properties are defined as follows:
The class loader used to locate, load, and instantiate providers
private ClassLoader loader;
Cached providers, in instantiation order
private linkedhashmap<string,s> providers = new linkedhashmap<& gt; ();
The current Lazy-lookup iterator
private lazyiterator lookupiterator;
Next look at the implementation code for the Serviceloader inner class Lazyiterator, as follows:
Private Inner class implementing Fully-lazy Provider Lookup//Private class Lazyiterator implements-iterator<s& Gt
{class<s> service;
ClassLoader loader;
Enumeration<url> configs = null;
Iterator<string> pending = null;
String nextname = null;
Private Lazyiterator (class<s> service, ClassLoader loader) {this.service = service;
This.loader = loader;
public Boolean Hasnext () {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;
Public S Next () {if (!hasnext ()) {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 subt
Ype ");
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} is public void remove () {throw new unsupportedoperationexception (); }
}
Where the PREFIX is defined as follows:
private static final String PREFIX = "meta-inf/services/";
2, Serviceloader iterator method
When executing iterator it = Serviceloader.iterator (); Code, the Serviceloader iterator method is executed, and the code is as follows:
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 ();}}
Returns a iterator anonymous class, iterator Hasnext () method
while (It.hasnext ()) {
Demoservice Demoservice = It.next ();
}
It.hasnext () invokes the public Boolean Hasnext () method of the new iterator () that is returned above. iterator Next Method
It.next (); the public S Next () method of the new iterator () returned above is invoked.