1 Introduction
This is the source notes] [JDK source of interpretation of the first article, this article, we explore related to Java source code of SPI mechanisms.
2 What is the mechanism for SPI
So, what is SPI mechanism?
Service Provider Interface SPI is short, that the service provider interface meaning.
According to the literal meaning we may be a little confused, SPI that white is an extension mechanism, we defined the class that implements an interface in the appropriate configuration file, and then load the instance of the class based on this interface to the configuration file and instantiate In fact SPI is such a thing.
Speaking SPI mechanism, our most common is Java-SPI mechanisms, in addition, SPI mechanism Dubbo and SpringBoot custom.
With SPI mechanism, then it offers the possibility for a number of flexible and extensible framework, rather than some of the framework implementation class will write the code inside died.
So, some framework is how to use the mechanism to be flexible SPI extend it? Here are a few chestnuts to elaborate at:
-
JDBC driver loading case : the use of Java SPI mechanism, we can introduce different JDBC driver package based on a different database vendors;
-
SpringBoot of SPI mechanism : we can
spring.factories
add class to automatically configure our custom, event listeners or initializer like; -
SPI mechanism of Dubbo : Dubbo SPI mechanism has even applied thoroughly , Dubbo basically their point of each function provides extension points, such as providing clustering extensions, routing and load balancing expansion expansion expansion almost close to 30 points. If one of the built in Dubbo implementation does not meet our needs, so we only use its SPI mechanism will achieve our implementation can replace Dubbo.
The above three chestnuts let us feel at some intuitive framework for the use of SPI mechanism is how to be flexible extensions.
3 How to use Java in SPI?
Let's look at how to use Java comes with SPI. First a definition of Developer
the interface
// Developer.java
package com.ymbj.spi;
publicinterface Developer {
void sayHi();
}
Redefinition two Developer
two interface implementation class:
// JavaDeveloper.java
package com.ymbj.spi;
publicclass JavaDeveloper implements Developer {
@Override
public void sayHi() {
System.out.println("Hi, I am a Java Developer.");
}
}
// PythonDeveloper.java
package com.ymbj.spi;
publicclass PythonDeveloper implements Developer {
@Override
public void sayHi() {
System.out.println("Hi, I am a Python Developer.");
}
}
Then the project resources
a new directory under a META-INF/services
folder, and then to create a Developer
fully qualified name of the interface named file, the file contents:
// com.ymbj.spi.Developer文件
com.ymbj.spi.JavaDeveloper
com.ymbj.spi.PythonDeveloper
Finally, we then create a test class JdkSPITest
:
// JdkSPITest.java
publicclass JdkSPITest {
@Test
public void testSayHi() throws Exception {
ServiceLoader<Developer> serviceLoader = ServiceLoader.load(Developer.class);
serviceLoader.forEach(Developer::sayHi);
}
}
Running above the test class to run a successful outcome following screenshot:
By the above simple mechanism SPI Demo we know how to use Java to achieve the expansion point loading, recommend the following article: JAVA Supplements - About SPI mechanism, through this article, I believe we will have a Java-SPI deeper understanding, in particular JDBC driver to load this regard.
4 Java source code analysis of the mechanism of SPI
Through the front extension Developer
simple interface Demo, we see the Java SPI mechanisms to achieve with ServiceLoader
this class about, then we first look at the ServiceLoader
class structure of the code:
// ServiceLoader实现了【Iterable】接口
publicfinalclass ServiceLoader<S>
implements Iterable<S>{
privatestaticfinal String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
privatefinal Class<S> service;
// The class loader used to locate, load, and instantiate providers
privatefinal ClassLoader loader;
// The access control context taken when the ServiceLoader is created
privatefinal AccessControlContext acc;
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// The current lazy-lookup iterator
private LazyIterator lookupIterator;
// 构造方法
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
// ...暂时省略相关代码
// ServiceLoader的内部类LazyIterator,实现了【Iterator】接口
// Private inner class implementing fully-lazy provider lookup
privateclass LazyIterator
implements Iterator<S>{
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;
}
// 覆写Iterator接口的hasNext方法
public boolean hasNext() {
// ...暂时省略相关代码
}
// 覆写Iterator接口的next方法
public S next() {
// ...暂时省略相关代码
}
// 覆写Iterator接口的remove方法
public void remove() {
// ...暂时省略相关代码
}
}
// 覆写Iterable接口的iterator方法,返回一个迭代器
public Iterator<S> iterator() {
// ...暂时省略相关代码
}
// ...暂时省略相关代码
}
It can be seen ServiceLoader
implements Iterable
the interface, which override iterator
method can produce an iterator; the same time ServiceLoader
there is an internal class LazyIterator
, but LazyIterator
also to achieve the Iterator
interface description LazyIterator
is an iterator.
4.1 ServiceLoader.load way to make early preparations to load the service provider implementation class
Then the source SPI mechanisms we now begin to explore Java, the first look at JdkSPITest
the first sentence of the code ServiceLoader<Developer> serviceLoader = ServiceLoader.load(Developer.class);
in the ServiceLoader.load(Developer.class)
source code:
// ServiceLoader.java
publicstatic <S> ServiceLoader<S> load(Class<S> service) {
//获取当前线程上下文类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// 将service接口类和线程上下文类加载器作为参数传入,继续调用load方法
return ServiceLoader.load(service, cl);
}
Let us look at the ServiceLoader.load(service, cl);
methods:
// ServiceLoader.java
publicstatic <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader)
{
// 将service接口类和线程上下文类加载器作为构造参数,新建了一个ServiceLoader对象
return new ServiceLoader<>(service, loader);
}
Continue to look at new ServiceLoader<>(service, loader);
is how it was built?
// ServiceLoader.java
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
It can be seen in the construction of ServiceLoader
an object property assignment in addition to its members, but also calls the reload
method:
// ServiceLoader.java
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
It can be seen in the reload
approach and created a new LazyIterator
object, and then assigned to lookupIterator
.
// ServiceLoader$LazyIterator.java
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
Can be seen in the construction of LazyIterator
an object, only to its member variables service
and loader
attribute assignment Yeah, we source all the way down now, I did not see to META-INF/services
the folder to load Developer
the interface implementation class! This is strange, we are ServiceLoader
the load
method name fool you.
Remember when a new analysis of previous code LazyIterator
object? Lazy
As the name suggests is a lazy meaning Iterator
is the meaning of iterations. We guess that at this time LazyIterator
the role of the object is when iteration should go to load Developer
class that implements the interface.
4.2 ServiceLoader.iterator method, implement lazy loading service provider implementation class
We now look at JdkSPITest
the second sentence of the code serviceLoader.forEach(Developer::sayHi);
, after the final implementation of this code will call serviceLoader
the iterator
method:
// serviceLoader.java
public Iterator<S> iterator() {
returnnew Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
returntrue;
// 调用lookupIterator即LazyIterator的hasNext方法
// 可以看到是委托给LazyIterator的hasNext方法来实现
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
// 调用lookupIterator即LazyIterator的next方法
// 可以看到是委托给LazyIterator的next方法来实现
return lookupIterator.next();
}
public void remove() {
thrownew UnsupportedOperationException();
}
};
}
It can be seen calling serviceLoader
the iterator
method returns an anonymous iterator object, and this anonymous iterator object is actually the equivalent of a facade class, which override hasNext
and the next
methods they were commissioned LazyIterator
of hasNext
and next
methods to achieve.
We continue to debug, found next will enter LazyIterator
the hasNext
method:
// serviceLoader$LazyIterator.java
public boolean hasNext() {
if (acc == null) {
// 调用hasNextService方法
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
Continue to follow up hasNextService
method:
// serviceLoader$LazyIterator.java
private boolean hasNextService() {
if (nextName != null) {
returntrue;
}
if (configs == null) {
try {
// PREFIX = "META-INF/services/"
// service.getName()即接口的全限定名
// 还记得前面的代码构建LazyIterator对象时已经给其成员属性service赋值吗
String fullName = PREFIX + service.getName();
// 加载META-INF/services/目录下的接口文件中的服务提供者类
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
// 还记得前面的代码构建LazyIterator对象时已经给其成员属性loader赋值吗
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
returnfalse;
}
// 返回META-INF/services/目录下的接口文件中的服务提供者类并赋值给pending属性
pending = parse(service, configs.nextElement());
}
// 然后取出一个全限定名赋值给LazyIterator的成员变量nextName
nextName = pending.next();
returntrue;
}
It can be seen in the implementation LazyIterator
of hasNextService
the time the method will eventually go to META-INF/services/
the directory load the contents of the interfaces file that is loaded service provider implements the fully qualified name of the class, and then remove the fully qualified name of a service provider implementation class assigned to the LazyIterator
member variable nextName
.
Here, and we understand the LazyIterator
role is really lazy loading, when used to load will really service provider implementation class.
Thoughts : Why use lazy load it here? Lazy loading of thinking what is it? Lazy loading so what good is it? You can also cited other cases of lazy loaded it?
Similarly, the implementation of End LazyIterator
of hasNext
the process will proceed to LazyIterator
the next
method:
// serviceLoader$LazyIterator.java
public S next() {
if (acc == null) {
// 调用nextService方法
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
We continue to follow up nextService
method:
// serviceLoader$LazyIterator.java
private S nextService() {
if (!hasNextService())
thrownew NoSuchElementException();
// 还记得在hasNextService方法中为nextName赋值过服务提供者实现类的全限定名吗
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
// 【1】去classpath中根据传入的类加载器和服务提供者实现类的全限定名去加载服务提供者实现类
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 subtype");
}
try {
// 【2】实例化刚才加载的服务提供者实现类,并进行转换
S p = service.cast(c.newInstance());
// 【3】最终将实例化后的服务提供者实现类放进providers集合
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
thrownew Error(); // This cannot happen
}
See LazyIterator
the nextService
method of example implementation class will eventually service provider prior to loading, and into providers
the collection, and then calls the method (referred to herein as a service provider, such as the implementation class of JavaDeveloper
the sayHi
method).
Note that this is a loaded service provider implementation class, if main
there is a method to call the service provider implementation class of functions, it will immediately call methods; then continues at instantiate a service provider class.
Thus we see the ServiceLoader.iterator
method really took to load and instantiate a META-INF/services/
service provider interface files in the directory defined in the implementation class.
Design pattern : see, Java's implementation code mechanism SPI applied iterative mode, Iterator shield structural differences inside the various storage objects, providing a unified view of the object to traverse the respective storage (storage object may be set , arrays, etc.).
java.util.Iterator
Also iterator pattern achieved: while Java each collection classes generally implementsIterable
the interface, implements itsiterator
methods to obtain aIterator
class that implements interface object (typically as a set of inner classes), then useIterator
the implementation class of the objecthasNext
andnext
method to traverse the collection element.
5 JDBC driver to load source code interpretation
SPI previous analysis of the source code of Java implementation mechanism, now the actual case SPI mechanism we will look at Java applications.
As we all know, JDBC driver loading is a typical Java application case of SPI mechanisms. JDBC provides a major interface specification, and this specification in the java api core library ( rt.jar
realization), whereas a different database vendors as long to write this driver code in line with JDBC interface specification, it can be used to connect the Java language the database.
java core library ( rt.jar
) to load the JDBC driver with the core interfaces and classes are java.sql.Driver
interfaces and java.sql.DriverManager
classes, which java.sql.Driver
are each database vendor's driver class to implement an interface, and DriverManager
is used to manage the database driver class, it is noteworthy that DriverManager
this class has a registeredDrivers
set of attributes, for driving the Mysql class stores.
// DriverManager.java
// List of registered JDBC drivers
privatefinalstatic CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
Here to analyze the source code to load the JDBC driver loaded Mysql driver for example.
Introducing our project mysql-connector-java
dependency (version is here 5.1.47
after), the drive Mysql implementation class file as shown below:
Mysql driver package can see there are two Driver
driving classes, respectively com.mysql.jdbc.Driver
, and com.mysql.fabric.jdbc.FabricMySQLDriver
, by default, we generally use only the former.
The SPI 5.1 using Java class loading drive Mysql
So then we have to explore how the code under JDBC driver loading is achieved.
First look at a simple JDBC test code:
// JdbcTest.java
publicclass JdbcTest {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
// 注意:在JDBC 4.0规范中,这里可以不用再像以前那样编写显式加载数据库的代码了
// Class.forName("com.mysql.jdbc.Driver");
// 获取数据库连接,注意【这里将会加载mysql的驱动包】
/***************【主线,切入点】****************/
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "123456");
// 创建Statement语句
statement = connection.createStatement();
// 执行查询语句
rs = statement.executeQuery("select * from user");
// 遍历查询结果集
while(rs.next()){
String name = rs.getString("name");
System.out.println(name);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
// ...省略释放资源的代码
}
}
}
In JdbcTest
the main
function call DriverManager
of getConnection
time method, performed this time is bound to DriverManager
a static class code block code, and then execute getConnection
the method, the first look at DriverManager
the static code block:
// DriverManager.java
static {
// 加载驱动实现类
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
Continue to follow up loadInitialDrivers
the code:
// DriverManager.java
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
// 来到这里,是不是感觉似曾相识,对,没错,我们在前面的JdkSPITest代码中执行过下面的两句代码
// 这句代码前面已经分析过,这里不会真正加载服务提供者实现类
// 而是实例化一个ServiceLoader对象且实例化一个LazyIterator对象用于懒加载
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
// 调用ServiceLoader的iterator方法,在迭代的同时,也会去加载并实例化META-INF/services/java.sql.Driver文件
// 的com.mysql.jdbc.Driver和com.mysql.fabric.jdbc.FabricMySQLDriver两个驱动类
/****************【主线,重点关注】**********************/
Iterator<Driver> driversIterator = loadedDrivers.iterator();
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
returnnull;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
In the above code, we can see Mysql drive mainly using Java class loading mechanism implemented in SPI, i.e. use ServiceLoader
to achieve load and instantiate the driver class Mysql.
5.2 Registration Mysql driving class
So, just above code to load and instantiate the class Mysql driver, then the driver class and how to be registered into DriverManager
the registeredDrivers
collection of it?
At this point, we note that com.mysql.jdbc.Driver
the class which also has a static block of code, that will certainly trigger the execution of the static code block of code when you instantiate the class, then we look at the direct static block of code to do something:
// com.mysql.jdbc.Driver.java
// Register ourselves with the DriverManager
static {
try {
// 将自己注册进DriverManager类的registeredDrivers集合
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
thrownew RuntimeException("Can't register driver!");
}
}
It can be seen, but it was Mysql driver class com.mysql.jdbc.Driver
is instantiated when its use when the time to perform static code block will register itself into DriverManager
the registeredDrivers
collection.
Well, continue to follow DriverManager
the registerDriver
method:
// DriverManager.java
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
// 继续调用registerDriver方法
registerDriver(driver, null);
}
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
// 将driver驱动类实例注册进registeredDrivers集合
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
thrownew NullPointerException();
}
println("registerDriver: " + driver);
}
Analysis here, and we understand how Java is loaded drive mechanism of SPI class Mysql and Mysql how to drive class registration into DriverManager
the registeredDrivers
collection.
Previously registered 5.3 Mysql database connection driver class
Since Mysql driver class has been registered come in, then when will it be used?
We want to connect Mysql database, the natural need to use the driver class Mysql, right. At this point we return to the test code JDBC JdbcTest
class of connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "123456");
this code, a look at the getConnection
source code:
// DriverManager.java
@CallerSensitive
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
// 继续调用getConnection方法来连接数据库
return (getConnection(url, info, Reflection.getCallerClass()));
}
Continue to follow up getConnection
method:
// DriverManager.java
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
thrownew SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
// Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
// 遍历registeredDrivers集合,注意之前加载的Mysql驱动类实例被注册进这个集合
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
// 判断有无权限
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
// 利用Mysql驱动类来连接数据库
/*************【主线,重点关注】*****************/
Connection con = aDriver.driver.connect(url, info);
// 只要连接上,那么加载的其余驱动类比如FabricMySQLDriver将会忽略,因为下面直接返回了
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
thrownew SQLException("No suitable driver found for "+ url, "08001");
}
Can be seen, DriverManager
the getConnection
method will be from registeredDrivers
out Mysql just loaded class driver set is connected to the database.
Well, here, JDBC drivers loaded on the basic source code analysis finished.
6 thread context class loader
The basic analysis done earlier source JDBC driver is loaded, but there is a very important knowledge not explain that parents undermine class loading mechanism of the delegation model thread context class loader .
As we all know, JDBC-related class specifications (such as front java.sql.Driver
and java.sql.DriverManager
) are in Jdk the rt.jar
lower cladding, means that the class will be class loader (BootstrapClassLoader) Load Startup; and Mysql class implements driven by an external database vendors, when driving when the class is to introduce the project is located in the project classpath
, in which case the boot class loader is certainly not possible to load these drivers like ah, this time how to do?
As the parent class loading mechanism delegation defect model in this regard, we can only break a parent delegation model. Because the project classpath
in class is to be loaded by the application class loader (AppClassLoader), so can we "reverse" Let's start the class loader delegate application class loader to load these external database vendor driver class it? If so, how can we do so that we start the class loader delegate application class loader to load classpath
classes in it?
The answer is definitely yes, we can set the application class loader into the inside thread, the thread that is inside a newly defined attribute class loader contextClassLoader
, then at a certain time to the application class loader is set into the thread of contextClassLoader
the property inside, If no, then the default is the application class loader.
And then start the class loader to load java.sql.Driver
and java.sql.DriverManager
when other types, but also removed from the current thread contextClassLoader
that is application class loader to classpath
load JDBC driver class provided by outside vendors. Therefore, the delegation model by destroying the class loading mechanism of parents, using the thread context class loader is the perfect solution to the problem.
At this point we go back and look at what time get thread context class loader when loading Mysql drive it?
The answer is in DriverManager
the loadInitialDrivers
method calls ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
this code, and remove the thread context class loader is in ServiceLoader
the load
approach taken:
publicstatic <S> ServiceLoader<S> load(Class<S> service) {
// 取出线程上下文类加载器取出的是contextClassLoader,而contextClassLoader装的应用程序类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// 把刚才取出的线程上下文类加载器作为参数传入,用于后去加载classpath中的外部厂商提供的驱动类
return ServiceLoader.load(service, cl);
}
So, here, and we understand that acts as a thread context class loader to load JDBC driver package in the role. In addition, we should know, Java vast majority involve the use of SPI are loaded thread context class loader to complete, such as JNDI, JCE, JBI and so on.
Extended : Breaking the class loading mechanism parent delegation model as well as hot deployment code, etc. In addition, Tomcat's class loading mechanism is also worth reading.
Note: If parents some minor partner of the delegation model class loading mechanism is not clear, it is recommended to fully understand the parents and delegation model in custom ClassLoader understand this text.
7 extension: Dubbo mechanism of SPI
Also talked about Dubbo front frame body is everywhere SPI application mechanism, it can be said everywhere extension point, really is the SPI application mechanism of the head. But Dubbo did not use the default Java mechanism of SPI, but their mechanism to achieve a set of SPI.
So, Dubbo Why not use the Java SPI mechanism?
There are two main reasons:
-
Java's SPI mechanism will be a one-time extension point to instantiate all realize, if extension initialization achieve very time-consuming, but also useless if loaded, would be a waste of resources;
-
The mechanism does not support Java SPI Ioc and AOP, so Dubbo with its own SPI mechanisms: increased support for the extension points of IoC and AOP, an extension point can be directly injected into the other setter extension points.
For these reasons, Dubbo from SPI defines a set of mechanisms for loading their own extension points. About SPI mechanism Dubbo's not go into details here, small partners who are interested can go to Dubbo official website to see how to extend the SPI Dubbo? As well as its official website also has Duboo of SPI source code analysis of the article.
8 Summary
Well, Java's SPI mechanism to interpret it here, in front of the first knowledge and then summarize:
1, the use of Java SPI mechanisms;
2 principle, Java's SPI mechanisms;
3, JDBC driver loading principle;
4, the SPI briefly Duboo mechanism.
Article from: Huperzine architecture notes