31-通过JDBC驱动加载深刻理解线程上下文类加载器机制

通过JDBC驱动加载深刻理解线程上下文类加载器机制

实例:
public class MyTest27 {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = 
           DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");
    }
}
  • 首先进入到Driver类中:
static {
   try {
      DriverManager.registerDriver(new Driver());  //执行Driver中的静态代码块
   } catch (SQLException var1) {
      throw new RuntimeException("Can't register driver!");
   }
}

//进入registerDriver方法之前,也会调用DriverManager中的静态代码块
/**
 * 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<String>() {
         public String run() {
            return System.getProperty("jdbc.drivers");  //首先这种方式的加载为 null
         }
      });
   } 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() {
         ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);  //★★★★
         Iterator<Driver> driversIterator = loadedDrivers.iterator();
         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类中的getConnection():
/**
	Attempts to establish a connection to the given database URL. The DriverManager attempts to 
	select an appropriate driver from the set of registered JDBC drivers.
*/
public static Connection getConnection(String url, String user, String password) throws SQLException {
   java.util.Properties info = new java.util.Properties();
   if (user != null) {
      info.put("user", user);
   }
   if (password != null) {
      info.put("password", password);
   }
   //Reflection.getCallerClass()这个方法是得到 调用该方法的类 的class对象。
   return (getConnection(url, info, Reflection.getCallerClass()));
}

//进入getConnection方法
private static Connection getConnection(
   String url, java.util.Properties info, Class<?> caller) throws SQLException {
   //得到调用该方法的类 的class对象的类加载器 这里class对象是MyTest27,加载它的加载器是 系统类加载器。
   ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; 
   synchronized(DriverManager.class) {
      // synchronize loading of the correct classloader.
      if (callerCL == null) {
         callerCL = Thread.currentThread().getContextClassLoader();
      }
   }
   
   if(url == null) {
      throw new SQLException("The url cannot be null", "08001");
   }
   
   println("DriverManager.getConnection(\"" + url + "\")");

   // Walk through the loaded registeredDrivers attempting to make a connection.
   // Remember the first exception that gets raised so we can reraise it.
   SQLException reason = null;

   //这里将会遍历registeredDrivers,registeredDrivers存放了到底有几个可用驱动,然后从中找到合适的驱动
   for(DriverInfo aDriver : registeredDrivers) {
      // If the caller does not have permission to load the driver then
      // skip it.
      //★ 这里为真的时候,才会真正的执行try里面的代码
      if(isDriverAllowed(aDriver.driver, callerCL)) {
         try {
            println("    trying " + aDriver.driver.getClass().getName());
            //进而获取数据库连接,通过connect方法获取,见下面的图
            Connection con = aDriver.driver.connect(url, info); 
            if (con != null) {
               // Success!
               println("getConnection returning " + aDriver.driver.getClass().getName());
               return (con);
            }
         } catch (SQLException ex) {
            if (reason == null) {
               reason = ex;
            }
         }

      } else {
         println("    skipping: " + aDriver.getClass().getName());
      }

   }

   // if we got here nobody could connect.
   if (reason != null)    {
      println("getConnection failed: " + reason);
      throw reason;
   }

   println("getConnection: no suitable driver found for "+ url);
   throw new SQLException("No suitable driver found for "+ url, "08001");
}

//进入isDriverAllowed方法,找个合适的驱动,并使用 classLoader(还是上面加载MyTest27的加载器:系统类加载器)
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
   boolean result = false;
   if(driver != null) {
      Class<?> aClass = null;
      try {
         //★使用系统类加载器加载相应的驱动,并初始化 true .  这里的加载不是主要目的,目的是下面的★
         aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
      } catch (Exception ex) {
         result = false;
      }
	   //★ 就是为了避免类加载的时候的命名空间问题。
      //之前 driver已经被加载过了, 之前的加载和现在的要做的加载必须是用一个类加载器去加载
      result = ( aClass == driver.getClass() ) ? true : false;
   }

   return result;
}
  • connect方法:

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值