爲什麼寫?我就想看看,到底和普通建立當有啥區別,另外是否可以熱切換域名
普通的Mysql創建連接的過程:
public class Conn {
Connection con;
public Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("數據庫驅動加載成功");
} catch(ClassNotFoundException e){
e.printStackTrace();
}
try {
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8","root","");
System.out.println("數據庫連接成功");
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
}
Druid創建數據庫連接過程:
DruidDataSourceAutoConfigure配置實例化數據源DataSource,同時@Bean(initMethod = "init")會將init作爲初始化方法設置到AbstractBeanDefinition中initMethodName裏邊,所以在實例化DataSource之後,將執行DataSource的init方法進行初始化,初始化過程中會將調用DruidDriver.getInstance()方法觸發Druid數據庫驅動注入DriverManager.registerDriver(driver),之後會加載mysql數據庫驅動設置到druid datasource裏邊,但是這裏使用的不是Class.forName("com.mysql.jdbc.Driver"),而是使用線程上下文加載器Thread.currentThread().getContextClassLoader()進行loadClass,Class.forName會觸發靜態初始化塊,上下文類加載器默認不會觸發靜態初始化塊,而之後的newInstance實例化mysql驅動的過程會調用靜態初始化塊進行註冊。
druid在獲取數據庫連接的時候直接調用mysql驅動實現類NonRegisteringDriver獲取。而不是DriverManager進行獲取,當然DriverManager的獲取方式的底層實現仍然是通過NonRegisteringDriver進行獲取的。但是這裏邊總感覺失去了DriverManager的靈魂判斷
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
boolean result = false;
if(driver != null) {
Class<?> aClass = null;
try {
aClass = Class.forName(driver.getClass().getName(), true, classLoader);
} catch (Exception ex) {
result = false;
}
// 注意,只有同一個類加載器中的Class使用==比較時纔會相等,此處就是校驗用戶註冊Driver時該Driver所屬的類加載器與調用時的是否同一個,DriverManager是被Bootstrap類加載器加載的,也就是說isDriverAllowed的執行加載器是Bootstrap,而傳參classLoader是上下文加載器,很有趣的是,上下文加載器可以破壞雙親委託機制。
result = ( aClass == driver.getClass() ) ? true : false;
}
return result;
}
那還有個疑問,如果使用域名作爲數據庫連接,是否可以不重啓服務而切換域名呢,可以。原因Druid存在一個wait重試線程CreateConnectionThread,當斷開連接後,獲取線程會執行activeCount--當activeCount <= minIdle最小連接數時候,會執行empty.signal(),將CreateConnectionThread被喚起,重新進行連接建立,而MysqlIO在執行socketFactory.connect(this.host, this.port, props);的時候會使用InetAddress.getAllByName(this.host)進行DNS域名解析