线程上下文类加载器----Jvm

1.为什么会有上下文类加载器?

在双亲委托模型下,类的加载是由上而下的,即下层的类加载器会委托上层去加载,但是对于SPI(Service Provider Interface)来说,有些接口是java核心库所提供的;而Java核心库是由启动类加载器加载的,但是这些接口的实现来自于不同的jar包(厂商提供),java启动类 加载器不会加载其他来源的jar包(这些jar包由上下文类加载器加载),这样传统的双亲委托模型就无法满足SPI的要求,而通过当前线程设置上下文类加载器,就可以由设置的上下文类加载器来实现对于接口实现类的加载。
在这里插入图片描述
问题: 它是如何打破了双亲委派模型?又是如何逆向使用类加载器了?
直到今天看了jdbc的驱动加载过程才茅塞顿开,其实并不复杂,只是一直没去看代码导致理解不够到位。

JDBC案例分析

我们先来看平时是如何使用mysql获取数据库连接的:

// 加载Class到AppClassLoader(系统类加载器),然后注册驱动类
// Class.forName("com.mysql.jdbc.Driver").newInstance(); 
String url = "jdbc:mysql://localhost:3306/testdb";    
// 通过java库获取数据库连接
Connection conn = java.sql.DriverManager.getConnection(url, "name", "password"); 

以上就是mysql注册驱动及获取connection的过程,各位可以发现经常写的Class.forName被注释掉了,但依然可以正常运行,这是为什么呢?这是因为从Java1.6开始自带的jdbc4.0版本已支持SPI服务加载机制,只要mysql的jar包在类路径中,就可以注册mysql驱动。

那到底是在哪一步自动注册了mysql driver的呢?
重点就在DriverManager.getConnection()中。需要明确的是java.sql.DriverManager位于rt.jar包目录下,该目录下的所有类均由Bootstrap启动类加载器进行加载。
我们都是知道调用类的静态方法会初始化该类,进而执行其静态代码块,DriverManager的静态代码块就是:
java.sql.DriverManager包中:

static {
   
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
}

初始化方法loadInitialDrivers()的代码如下:

private static void loadInitialDrivers() {
   
    String drivers;
    try {
   
		// 先读取系统属性
		drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
   
            public String run() {
   
                return System.getProperty("jdbc.drivers");
            }
        });
    } catch (Exception ex) {
   
        drivers = null;
    }
    // 通过SPI加载驱动类
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
   
        public Void run() {
   
            ServiceLoader<Driver> loadedDrivers = ServiceLoader
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值