一、SPI 是什么?
SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参考【EffectiveJava】page6),是一种将服务接口与服务实现分离以达到解耦、大大提升了程序可扩展性的机制。引入服务提供者就是引入了spi接口的实现者,通过本地的注册发现获取到具体的实现类,轻松可插拔。
二、数据库加载Demo
public class Demo1 {
private static String DB_URL="jdbc:mysql://127.0.0.1:3306/test?user=test&password=test";
private static String sql="select * from `pet`";
private static String DRIVERCLASS1="com.mysql.cj.jdbc.Driver";
private static String DRIVERCLASS2="com.mysql.jdbc.Driver";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//Class.forName(DRIVERCLASS1);
Connection connection=null;
try {
//连接MySQL数据库。有可能注册了多个Driver,这里通过遍历成功连接后返回
connection=DriverManager.getConnection(DB_URL);
//创建statement类对象,用来执行SQL语句
PreparedStatement statement = connection.prepareStatement(sql);
//ResultSet类,用来存放获取的结果集
ResultSet resultSet=statement.executeQuery();
List<Pet> list=new ArrayList<>();
}catch (Exception e){
e.printStackTrace();
}
connection.close();
}
1、java提供数据库连接接口java.sql.Driver
2、mysql数据库提供了Driver实现类com.mysql.cj.jdbc.Driver
3、在META-INF/services/下,创建java.sql.Driver文件,内容写上com.mysql.cj.jdbc.Driver,mysql实现类的全路径地址。
4、DriverManager内有一个静态代码块,在类加载时会jvm被执行
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
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;
}
// If the driver is packaged as a Service Provider, load it.
// Get all the drivers through the classloader
// exposed as a java.sql.Driver.class service.
// ServiceLoader.load() replaces the sun.misc.Providers()
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/* Load these drivers, so that they can be instantiated.
* It may be the case that the driver class may not be there
* i.e. there may be a packaged driver with the service class
* as implementation of java.sql.Driver but the actual class
* may be missing. In that case a java.util.ServiceConfigurationError
* will be thrown at runtime by the VM trying to locate
* and load the service.
*
* Adding a try catch block to catch those runtime errors
* if driver not available in classpath but it's
* packaged as service and that service is there in classpath.
*/
try{
//查找具体的实现类的全限定名称
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
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);
}
}
}
核心代码
//查找具体的provider,就是在META-INF/services/***.Driver文件中查找具体的实现。
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
ServiceLoader.load(Driver.class),查找具体的provider,就是在META-INF/services/***.Driver文件中查找具体的实现。遍历实现类,
private boolean hasNextService() {
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;
}
private S nextService() {
if (!hasNextService())
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 subtype");
}
try {
//实例化类,注册到DriverManager(
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
}
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
三、测试demo
1、新增接口
package com.riant.spi;
public interface ServiceSpi {
void show();
}
2、新增两个实现类
package com.riant.spi;
public class ServiceSpiA implements ServiceSpi {
@Override
public void show() {
System.out.println("A show");
}
}
package com.riant.spi;
public class ServiceSpiB implements ServiceSpi {
@Override
public void show() {
System.out.println("B show");
}
}
3、创建/META-INF/services/com.riant.spi.ServiceSpi 文件
可以修改具体实现类
4、test
public class TestServiceSpi {
public static void main(String[] args) {
final ServiceLoader<ServiceSpi> serviceSpis = ServiceLoader.load(ServiceSpi.class);
final Iterator<ServiceSpi> iterator = serviceSpis.iterator();
while (iterator.hasNext()){
final ServiceSpi next = iterator.next();
next.show();
}
}
}
可以看到结果