java类加载机制为什么双亲委派_为什么说JDBC驱动类加载破坏了双亲委派机制

大家都知道jdk的类加载机制是双亲委派机制,当我们需要加载一个类的时候,比如如下几种情况

new一个类的对象

调用类的静态成员(除了final常量)和静态方法

使用java.lang.reflect包的方法对类进行反射调用

当虚拟机启动,java Demo01,则一定会初始化Demo01类,加载main方法所在的类

当初始化一个类,如果其父类没有被初始化,则先初始化它父类

那么看一段代码:

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类的时候,会执行静态块

static {

loadInitialDrivers();

println("JDBC DriverManager initialized");

}

主要是这两行代码

ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);

Iterator driversIterator = loadedDrivers.iterator();

//我们看到这里使用了线程上下文加载器,为什么这里要这么做??如果不这么做会怎样?

public static ServiceLoader load(Class service) {

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

下面是java.util.ServiceLoader$LazyIterator.nextService()方法

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),那么这里默认使用的是调用方的类加载器,如下所示:

/**

* Returns the {@code Class} object associated with the class or

* interface with the given string name. Invoking this method is

* equivalent to:

*

*

* {@code Class.forName(className, true, currentLoader)}

*

*

* where {@code currentLoader} denotes the defining class loader of

* the current class.

*

*

For example, the following code fragment returns the

* runtime {@code Class} descriptor for the class named

* {@code java.lang.Thread}:

*

*

* {@code Class t = Class.forName("java.lang.Thread")}

*

*

* 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包下的类。 我不认为这是对双亲委派的破坏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值