他获取连接实际就两步,这里用postgreSQL的jdbc,其他的jdbc大体的流程应该都差不多的
在使用上通过下面两行代码我们就可以获取connection连接
Class.forName(
"org.postgresql.Driver"
);
Connection
c = DriverManager.getConnection("jdbc:postgresql://localhost:5432/pgsqltest", "postgres", "2016");
实际的执行过程在下面
第一步 class.forName("
org.postgresql.Driver
");注册驱动
首先通过class.forName("
org.postgresql.Driver");class.forName会要求JVM查找并加载指定的类,也就是说在这个过程中肯定的JVM会执行该类的静态代码段,
JAVA规范中明确规定:所有的驱动程序必须在静态初始化代码块中将驱动注册到驱动程序管理器中
,这样通过这个反射的方式,我们就把驱动给注册进来了
他具体的注册过程是这样的:
1、通过class.forName("
org.postgresql.Driver
")反射加载这个类
2、类加载进来后,会自动执行
Driver类的
静态代码块中的register这个静态方法
3、register方法中先判断是否注册过,如果没有则执行下面三行代码,可以看出来,这是单例模式, Driver registeredDriver = new Driver();
DriverManager.registerDriver(registeredDriver);
Driver.registeredDriver = registeredDriver;//Driver类定义的静态变量,引用指向自己,在deregister方法进行注销时可以用到
4、DriverManager.registerDriver(registeredDriver);执行这个方法时会加载
java.sql.DriverManager类
5、加载这个类后会先执行他的静态代码块,静态代码块中有一个loadInitialDrivers方法
6、loadInitialDrivers用于加载配置在jdbc.drivers系统属性内的驱动Driver,配置在jdbc.drivers中的驱动driver将会首先被加载,一般jdbc.drivers应该不会配置,因为正常的执行流程都只会加载一个我们自己想要加载的driver,我看网上好像也没有配置这个的
7、执行完静态代码块中的
loadInitialDrivers方法后就开始执行3中调用到的
registerDriver方法
8、直接调用的是这个方法public static synchronized void registerDriver(java.sql.Driver driver),在这个方法中,只有一个registerDriver(driver, null);方法,会转入重载的public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da)
9、执行registerDriver(java.sql.Driver driver, DriverAction da),驱动注册正式完成,我们可以注册多个驱动,这个驱动的注册实际就是将当前的
Driver类先放入DriverInfo类的实例化对象中,这个类就是一个bean对象,直接作为内部类定义在DriverManager类的末尾,然后将这个bean放入
DriverManager一开始定义的静态的
CopyOnWriteArrayList容器的
registeredDrivers中
,放入之后,在
DriverManager类中的其他方法中都可以看到从这个容器中
, 遍历拿出
driver使用
第二步
DriverManager.getConnection()获取连接
1、
DriverManager有四个getConnection()方法,前三个都只是对访问的一个转接,最终会将传入参数处理成统一格式后调用最后一个getConnection方法。
根据开发者传入参数不同,调用三个对开放的DriverManager.getConnection()其中的一个,传入参数可以是单独的url,也可以是url+properties或者是url+String user+String password .最后一个getConnection方法是私有的,这个方法才是有核心功能的
2、
前三个方法最终向私有getConnection方法传入的参数为
String url, java.util.Properties info以及
Reflection.getCallerClass() ,传入这个参数的目的是在方法里面获取该类的类加载器,用于判断注册驱动列表中哪一个是需要获取连接的驱动
Reflection.getCallerClass(),是反射中的一个方法,这个方法是native的,用来返回他的调用类,也就说是哪个类调用了这个方法,Reflection类位于调用栈中的0帧位置,在JDK7以前,该方法可以传入int n返回调用栈中从0帧开始的第n帧中的类,在JDK7中,需要设置java命令行选项Djdk.reflect.allowGetCallerClass来使用该方法,到了JDK8时,再调用该方法会导致UnsupportedOperationException异常。
JDK8中getCallerClass使用方法变更为getCallerClass(),Reflection.getCallerClass()方法调用所在的方法必须用@CallerSensitive进行注解,通过此方法获取class时会跳过链路上所有的有@CallerSensitive注解的方法的类,直到遇到第一个未使用该注解的类,避免了用Reflection.getCallerClass(int n) 这个过时方法来自己做判断。
在这里每个getConnection都是用CallerSensitive修饰的,调用getCallerClass应该是获取外面使用DriverManager.getConnection()的类的名称,即在class A中调用了DriverManager.getConnection(),则返回class A
3、
getConnection方法调用
caller.getClassLoader()方法获取传入类的类加载器,这里还涉及到了委派链的相关知识,如果无法获取到类加载器,将通过
Thread.currentThread().getContextClassLoader();获取线程上下文类加载器
然后在对驱动注册列表中注册的驱动类进行遍历,通过
isDriverAllowed(aDriver.driver, callerCL)方法判断列表中哪个驱动是当前请求获取连接的类所调用的驱动。
isDriverAllowed方法中获取了传入的驱动类的类加载器,首先通过aClass =
Class.forName(driver.getClass().getName(),
true, classLoader);方法获得类,该方法返回与给定字符串名的类或接口的Class对象,使用给定的类加载器进行加载,然后通过
result = ( aClass == driver.getClass() ) ?
true
:
false
;进行对比,只有同一个类加载器中的Class使用==比较时才会相等,此处就是校验用户注册Driver时该Driver所属的类加载器与调用时的是否为同一个
通过判断得到需要的驱动类,并调用Driver类的connect方法获取连接
4、
Driver类的connect方法中会先判断url前缀是否为jdbc:postgresql,然后通过将传入的properties中的属性信息,初始化给connect定义的Properties props,并getDefaultProperties方法为driver类中定义的properties进行扩权操作,简单来说就是保证其有足够权限读取资源,其中用到了AccessController.doPrivileged方法,它是一个在AccessController类中的静态方法,允许在一个类实例中的代码通知这个AccessController:它的代码主体是享受”privileged(特权的)”,它单独负责对它的可得的资源的访问请求,而不管这个请求是由什么代码所引发的。
这就是说,一个调用者在调用doPrivileged方法时,可被标识为 “特权”。在做访问控制决策时,如果checkPermission方法遇到一个通过doPrivileged调用而被表示为“特权”的调用者,并且没有上下文自变量,checkPermission方法则将终止检查。如果那个调用者的域具有特定的许可,则不做进一步检查,checkPermission安静地返回,表示那个访问请求是被允许的;如果那个域没有特定的许可,则象通常一样,一个异常被抛出。
5、
调用
acceptsURL方法,该方法对URL进行了校验与解析
6、
解析无误后会调用makeConnection方法获取连接。如果设置了等待连接时间,那么还会开启一个线程来调用makeConnection方法。
7、
makeConnection方法中只有一个简单的return new PgConnection(hostSpecs(props), user(props), database(props), props, url),返回的Connection类就是通常来说获取的连接
8、
PgConnection类实现了BaseConnection接口,该接口继承于PGConnection, Connection接口,在这个类的构造方法中,调用了QueryExecutor
org.
postgresql.
core.ConnectionFactory
.openConnection(hostSpecs, user, database, info)工厂方法返回连接:
this.queryExecutor = ConnectionFactory.openConnection(hostSpecs, user, database, info);
9、
ConnectionFactory类的openConnection方法中,返回了org.postgresql.core.QueryExecutor queryExecutor = org.postgresql.core.v3.ConnectionFactory.openConnectionImpl( hostSpecs, user, database, info);
10、
最终在org.postgresql.core.v3.ConnectionFactory类中的openConnectionImpl方法中真正实现了与数据库的交互,在这里完成了与数据库的连接