为什么写?我就想看看,到底和普通建立当有啥区别,另外是否可以热切换域名
普通的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域名解析