你們都知道jdk的類加載機制是雙親委派機制,當咱們須要加載一個類的時候,好比以下幾種狀況java
那麼看一段代碼:mysql
public static void main(String[] args) throws SQLException { String url = "jdbc:mysql://..."; String username = "root"; String password = "root"; Connection conn = null; try { conn = DriverManager.getConnection(url, username, password); PreparedStatement statement = conn.prepareStatement("select * from table where id = ?"); statement.setLong(1,615444000000000L); ResultSet set = statement.executeQuery(); while(set.next()){ System.out.println(set.getString("user_id")); } conn.close(); } catch (SQLException e) { e.printStackTrace(); } finally { if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
上面是一段標準的jdbc查詢代碼,在加載java.sql.DriverManager類的時候,會執行靜態塊sql
static { loadInitialDrivers(); println("JDBC DriverManager initialized"); }
主要是這兩行代碼app
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator<Driver> driversIterator = loadedDrivers.iterator(); //咱們看到這裏使用了線程上下文加載器,爲何這裏要這麼作??若是不這麼作會怎樣? public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); }
下面是java.util.ServiceLoader$LazyIterator.nextService()方法ide
private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; nextName = null; Class<?> c = null; try { c = Class.forName(cn, false, loader); } catch (ClassNotFoundException x) { fail(service, "Provider " + cn + " not found"); } if (!service.isAssignableFrom(c)) { fail(service, "Provider " + cn + " not a subtype"); } try { S p = service.cast(c.newInstance()); providers.put(cn, p); return p; } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated", x); } throw new Error(); // This cannot happen }
咱們看到了Class.forName(cn, false, loader)的調用,若是前面沒有用線程上下文加載器(也就是loader),那麼這裏默認使用的是調用方的類加載器,以下所示:ui
/** * Returns the {@code Class} object associated with the class or * interface with the given string name. Invoking this method is * equivalent to: * * <blockquote> * {@code Class.forName(className, true, currentLoader)} * </blockquote> * * where {@code currentLoader} denotes the defining class loader of * the current class. * * <p> For example, the following code fragment returns the * runtime {@code Class} descriptor for the class named * {@code java.lang.Thread}: * * <blockquote> * {@code Class t = Class.forName("java.lang.Thread")} * </blockquote> * <p> * A call to {@code forName("X")} causes the class named * {@code X} to be initialized. * * @param className the fully qualified name of the desired class. * @return the {@code Class} object for the class with the * specified name. * @exception LinkageError if the linkage fails * @exception ExceptionInInitializerError if the initialization provoked * by this method fails * @exception ClassNotFoundException if the class cannot be located */ @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
那麼若是沒有使用線程上下文加載器,其實用的就是調用方 ServiceLoader 的加載器,而ServiceLoader在java.util下面,是沒法加載com.mysql.jdbc包下的類。 我不認爲這是對雙親委派的破壞。this