public class DruidDriver implements Driver, DruidDriverMBean {
private final static DruidDriver instance = new DruidDriver();
/**
* 此方法将返回在DruidDriver中所定义的单例
* @return
*/
public static DruidDriver getInstance() {
return instance;
}
}
1.1 绕过安全机制,注册驱动
该方法所返回的是DruidDriver的静态单例,在静态代码块中可以找到以下代码,通过调用AccessController.doPrivileged()
方法绕过安全检查,调用本类中的注册驱动方法对当前实例进行注册。
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
registerDriver(instance);
return null;
}
});
}
2. 注册驱动
由于DruidDriver
实现了java.sql.Driver
接口,自然也允许自身被当做驱动由驱动管理器进行注册。
/**
* 注册驱动
* @param driver
* @return
*/
public static boolean registerDriver(Driver driver) {
try {
//利用驱动管理器进行注册驱动
DriverManager.registerDriver(driver);
try {
//创建MBeanServer(JMX相关内容)
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
//新建MBean ObjectName, 在MBeanServer里标识注册的MBean
ObjectName objectName = new ObjectName(MBEAN_NAME);
//如果MBean中没有注册过当前ObjectName,则将当前实例注入至MBean中
if (!mbeanServer.isRegistered(objectName)) {
mbeanServer.registerMBean(instance, objectName);
}
} catch (Throwable ex) {
if (LOG == null) {
LOG = LogFactory.getLog(DruidDriver.class);
}
LOG.warn("register druid-driver mbean error", ex);
}
return true;
} catch (Exception e) {
if (LOG == null) {
LOG = LogFactory.getLog(DruidDriver.class);
}
LOG.error("registerDriver error", e);
}
return false;
}
3.DriverManager注册驱动
DriverManager
的静态代码块中存在如下定义,loadInitialDrivers()
将负责加载这些驱动
/**
* 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");
}
通过查阅DriverManager
的文档注释以及loadInitialDrivers()
方法可知,在JDBC4.0驱动以后,可以通过META-INF/services/java.sql.Driver
文件指定由SPI机制加载的JDBC驱动。
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() {
//此处通过SPI机制加载经过配置的java.sql.Driver接口
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);
}
}
}
4.Druid是否还会加载其他的驱动
在DruidDataSource的初始化方法中,除了DruidDriver.getInstance(),还存在resolveDriver()
方法可以加载数据库驱动,此方法将通过所配置的driverClassName
加载驱动,如果未配置,则会根据url自动识别dbType,然后选择相应的driverClassName
。
通过此处加载的驱动,与DriverManager利用SPI机制加载的对象不一致
protected void resolveDriver() throws SQLException {
//如果当前连接池没有指向驱动对象,则动态加载驱动
if (this.driver == null) {
//如果当前没有指定驱动,则会根据所配置的jdbcUrl进行匹配,
if (this.driverClass == null || this.driverClass.isEmpty()) {
//此处的匹配规则是通过jdbcUrl开头的标记进行判断,当他符合某一驱动标记时,则返回对应的驱动
this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl);
}
//由于Druid内置了一个Mock驱动,此处是为Mock驱动提供支持
if (MockDriver.class.getName().equals(driverClass)) {
driver = MockDriver.instance;
} else if ("com.alibaba.druid.support.clickhouse.BalancedClickhouseDriver".equals(driverClass)) {
//此处为Druid内置的ClickHouse负载均衡驱动
Properties info = new Properties();
info.put("user", username);
info.put("password", password);
info.putAll(connectProperties);
driver = new BalancedClickhouseDriver(jdbcUrl, info);
} else {
if (jdbcUrl == null && (driverClass == null || driverClass.length() == 0)) {
throw new SQLException("url not set");
}
//此时通过类加载器与指定的驱动进行匹配,如果driverClassLoader为空,则取当前线程的ContextClassLoader
driver = JdbcUtils.createDriver(driverClassLoader, driverClass);
}
} else {
//如果有加载驱动,但是为配置驱动名,则从驱动中进行获取
if (this.driverClass == null) {
this.driverClass = driver.getClass().getName();
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)