你们都知道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