本文主要探讨java.sql.DriverManager和java.sql.Driver类
背景:
我在实际项目中采用druid+mysql,简单代码如下:
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DruidDataSource dataSource() throws Exception {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setName(MybatisHelp.name);
druidDataSource.setUsername(MybatisHelp.username);
druidDataSource.setPassword(MybatisHelp.password);
druidDataSource.setUrl(MybatisHelp.url);
druidSettings(druidDataSource);
return druidDataSource;
}
public void druidSettings(DruidDataSource druidDataSource) throws Exception {
druidDataSource.setMaxActive(28);
druidDataSource.setInitialSize(2);
druidDataSource.setUseUnfairLock(Boolean.TRUE);
druidDataSource.setMinIdle(1);
druidDataSource.setMaxWait(12000);
druidDataSource.setPoolPreparedStatements(Boolean.FALSE);
druidDataSource.setTestOnBorrow(Boolean.FALSE);
druidDataSource.setTestOnReturn(Boolean.FALSE);
druidDataSource.setTestWhileIdle(Boolean.TRUE);
druidDataSource.setTimeBetweenEvictionRunsMillis(30000L);
druidDataSource.setMinEvictableIdleTimeMillis(30000 * 4);
druidDataSource.setRemoveAbandoned(Boolean.TRUE);
druidDataSource.setRemoveAbandonedTimeout(180);
druidDataSource.setLogAbandoned(Boolean.TRUE);
druidDataSource.setFilters("stat");
//每10分钟自动将监控的数据存储到日志中
druidDataSource.setTimeBetweenLogStatsMillis(60000 * 60);
druidDataSource.setDriver(new Driver());
}
DriverManager
- managing a set of JDBC drivers
- JDBC 2.0 API, provides another way to connect to a data source. The use of a javax.sql.DataSource
- Applications no longer need to explicitly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
/**
* Load the initial JDBC drivers by checking the System property
* jdbc.properties and then use the {@code ServiceLoader} mechanism
*/
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
由静态代码块触发加载初始化驱动,具体如下:
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction() {
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() {
public Void run() {
ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);
Iterator 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);
}
}
}
可以看到在DriverManager初始化的时候会加载JDBC drivers,属性来自于System.getProperty("jdbc.drivers"),并使用ServiceLoader机制(SPI,后续会讲解到)
断点进去会发现初始化代码走完发现driver是null,而我们的driver的真正生成是在实现的代码里面触发,如下:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
/**
* Construct a new driver and register it with DriverManager
*
* @throws SQLException
* if a database error occurs.
*/
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
/**
* Registers the given driver with the {@code DriverManager}.
* A newly-loaded driver class should call
* the method {@code registerDriver} to make itself
* known to the {@code DriverManager}. If the driver is currently
* registered, no action is taken.
*
* @param driver the new JDBC Driver that is to be registered with the
* {@code DriverManager}
* @exception SQLException if a database access error occurs
* @exception NullPointerException if {@code driver} is null
*/
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
registerDriver(driver, null);
}
此处由实现类触发,这里的例子通过druid配置mysql
/**
* Registers the given driver with the {@code DriverManager}.
* A newly-loaded driver class should call
* the method {@code registerDriver} to make itself
* known to the {@code DriverManager}. If the driver is currently
* registered, no action is taken.
*
* @param driver the new JDBC Driver that is to be registered with the
* {@code DriverManager}
* @param da the {@code DriverAction} implementation to be used when
* {@code DriverManager#deregisterDriver} is called
* @exception SQLException if a database access error occurs
* @exception NullPointerException if {@code driver} is null
* @since 1.8
*/
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) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
加载完后:
SPI
首先贴上mysql包的扩展内容
SPI的相关内容推荐
奶芋的 文章:https://mp.weixin.qq.com/s/8rrHhgUn4VxEgBlw_Oe-qQ
http://www.cnblogs.com/zhongkaiuu/articles/5040971.html