Motan Source Analysis II: Using the SPI mechanism for class loading
Motan in the source code used a lot of SPI mechanism for the creation of objects, below we have a concrete analysis of its implementation methods.
1. In the actual jar package in the \meta-inf\services directory to introduce related files, such as the following image, I extracted the core jar file after the corresponding file list:
2. In the first section of the Confighandler as an example to analyze, Open the Com.weibo.api.motan.config.handler.ConfigHandler file in the previous figure, which identifies the implementation class for the Confighandler interface as: COM.WEIBO.API.MOTAN.CONFIG.HANDLER.S Impleconfighandler 1 2 3 4 5 6 7 8 9 A # # copyright 2009-2016 Weibo, Inc. #&n bsp; licensed under the Apache License, version 2.0 (the "License"); # you are not use this file except in compliance with the License. # obtain a copy of the License at # # http://www.apac he.org/licenses/license-2.0 # # unless required by applicable and agreed to in writing, software #&nb sp; distributed under the License is distributed on an ' as is ' basis, # without Warranties or CONDITIONS of any KIND, either express OR implied. # the license for specific language governing permissions and # limitations under the License. # Com.weibo.api.motan.config.handler.SimpleConfigHandler
3. In the first section, the code to create the Confighandler object is this:
Confighandler Confighandler = Extensionloader.getextensionloader (Confighandler.class). GetExtension ( Motanconstants.default_value);
4. Start into the core of the actual load code, first look at the specific implementation of the ClassLoader:
public static <T> extensionloader<t> getextensionloader (class<t> type) {Checkinterfacetype ( type);//basic check extensionloader<t> loader = (extensionloader<t>) extensionloaders.get (type);//Whether it has been loaded before This loader if (loader = = null) {loader = Initextensionloader (type);//First Load} return loader
; private static <T> void Checkinterfacetype (class<t> clz) {if (CLZ = = null) {Failt
Hrows (CLZ, "Error extension type is null");
} if (!clz.isinterface ()) {failthrows (CLZ, "Error extension type is not interface");
} if (!isspitype (CLZ)) {failthrows (CLZ, "Error extension type without @Spi annotation");
} public static synchronized <T> extensionloader<t> Initextensionloader (class<t> type) {
extensionloader<t> loader = (extensionloader<t>) extensionloaders.get (type); if (loader = = null) {loader = new extensionloader<t> (type);//A newly created loader extensionloaders.
Putifabsent (type, loader);
Loader = (extensionloader<t>) extensionloaders.get (type);
return loader; }
5. Below we will go to the inside of the loader to analyze the specific implementation:
Private Extensionloader (class<t> type) {This (type, Thread.CurrentThread (). Getcontextclassloader ())//Use
The class loader for the current thread is the loader, type is Confighandler interface} public T getextension (String name) {checkinit ();//Check initialization
if (name = = NULL) {return null;
try {SPI SPI = type.getannotation (Spi.class);
if (spi.scope () = = Scope.singleton) {return getsingletoninstance (name);//Returns a unique object} else {
class<t> CLZ = extensionclasses.get (name);
if (CLZ = = null) {return null; return clz.newinstance ()///Recreate object} catch (Exception e) {failthrows (
Type, "Error when GetExtension" + name, e);
return null;
Private synchronized void loadextensionclasses () {if (init) {return; } extensionclasses = LoadextensiOnclasses (PREFIX)//loading related class singletoninstances = new Concurrenthashmap<string, t> ();
init = true; Private concurrentmap<string, class<t>> loadextensionclasses (string prefix) {string fullName = Prefix + type.getname ();//Full Name: Class List in jar package name +\meta-inf\services\com.weibo.api.motan.config.handler.confighandler file
<String> classnames = new arraylist<string> ();
try {enumeration<url> URLs;
if (ClassLoader = = null) {urls = classloader.getsystemresources (fullName);
else {urls = classloader.getresources (fullName); } if (url = null | |!urls.hasmoreelements ()) {return new concurrenthashmap<string, Clas
S<t>> ();
} System.out.println ("FullName:" +fullname);
while (Urls.hasmoreelements ()) {URL url = urls.nextelement (); System.Out.println ("URL:" +url.getfile ());
parseURL (type, URL, classnames); } catch (Exception e) {throw new Motanframeworkexception ("Extensionloader load
extensionclasses error, prefix: "+ prefix +" type: "+ type.getclass (), E);
for (String classn:classnames) {System.out.println ("class:" +CLASSN);
Return LoadClass (Classnames); }
6. Read the contents of the file in the parseURL method and complete the load of the class in LoadClass
private void parseURL (class<t> type, url url, list<string> classnames) throws Serviceconfigurationerror {
InputStream inputstream = null;
BufferedReader reader = null;
try {InputStream = Url.openstream ();
reader = new BufferedReader (new InputStreamReader (InputStream, Motanconstants.default_character));
String line = null;
int IndexNumber = 0;
while (line = Reader.readline ())!= null) {indexnumber++; ParseLine (type, URL, line, IndexNumber, classnames); Read to class name: Com.weibo.api.motan.config.handler.SimpleConfigHandler}} catch (Exception x) {F
Aillog (Type, "Error reading SPI configuration file", x);
Finally {try {if (reader!= null) {reader.close ();
} if (InputStream!= null) {inputstream.close (); The catch (IOException y) {faillog (type, "Error closing SPI configuration file", y); }} private Concurrentmap<string, class<t>> loadclass (list<string> classnames)
{concurrentmap<string, class<t>> map = new concurrenthashmap<string, class<t>> ();
for (String classname:classnames) {try {class<t> clz; if (ClassLoader = = null) {CLZ = (class<t>) class.forname (className);//Load class: COM.WEIBO.API.MOTAN.C Onfig.handler.SimpleConfigHandler} else {clz = (class<t>) class.forname (classn
Ame, True, ClassLoader);
} checkextensiontype (CLZ);
String spiname = Getspiname (CLZ);
if (Map.containskey (Spiname)) {failthrows (CLZ, ": Error spiname already" + exist); else {map.put (spiname, CLZ);
The catch (Exception e) {faillog (type, Error load SPI class, E);
} return map; }
Summary of knowledge points for Motan class loading:
1. Using the SPI specification of JDK, add the actual usage class description in \meta-inf\services, thus realizing the complete decoupling between class and class;
2. The class loader uses the class loader of the current thread;
The 3.motan ClassLoader can support both single and multiple modes;
The class loading method for SPI is heavily used in 4.motan.