嗯,class文件是通过【类加载器】装载到jvm中的
为了防止内存中存在多份同样的字节码,所以要使用双亲委派机制(它不会自己去尝试加载类,而且把请求委托给父类加载器去完成,依次向上)
JDK中的本地方法类一般由根加载器(Bootstrap Classloader)装载,JDK中内部实现的扩展类一般由扩展类加载器(Ext ClassLoader)实现装载,程序中的类文件有系统加载器(App ClassLoader)实现装载
也就是如下图的样子:
经常听说打破双亲委派机制?是啥意思?
正常的加载顺序是:从APPClassLoader->Ext ClassLoader->BootStrap ClassLoader 这个顺序找,打破这个顺序,就是打破双亲委派机制,加载class的核心方法在loaderClass类的loadClass方法上,只需要自定义一个ClassLoader,重新loadClass方法,就可以打破双亲委派机制了。
那什么场景会打破双亲委派机制呢?
最经典的就是tomcat了 一个tomcat下可以启动多个程序 tomcat给每个web应用创建了一个类加载器实例(WebAppClassLoader),改加载器重写了loadClass方法,有先加载当前应用目录下的类,如果找不到了,才一层一层往上找。这样就做到了web应用层级的隔离。
一个有争议的JDBC
有的人说,JDBC打破了双亲委派机制,有的人又说它没有打破,为啥呢?
DBC定义了接口,具体事项由各个厂商进行实现(比如MySQL)
类加载的时候还有一个规则,就是一个类由类加载器A加载,那么它的依赖也是由相同的类加载器加载
在用JDBC的时候,是使用了DriverManager进而获取Connection,DriverManager在java.sql包下,显然是由BootStrap类加载器加载的
我们使用DriverManager.getConnection()时候,得到的一定是厂商实现的类,但是Bootstrap laoder 是加载不到这些类的,因为这些类不在java包中,那怎么得到的呢?
DriverManager的解决方案是,在DriverManager初始化的时候,得到[线程上线文加载器],去获取Connection的时候,是使用【线程上下文加载器】去加载Connection的,这里的上下文加载器就是AppClass loader,所以在获取Connection的时候,还是先找Ext ClassLoader和BootStrap ClassLoader,只不过这俩加载器肯定是加载不到的,最终会由App ClassLoader进行加载。
那么,它打破了双亲委派机制了吗?
猿,你怎么看?