双亲委派机制
双亲委派机制
violet一、基本概念
双亲委派机制是Java类加载器(ClassLoader)的核心工作模式,其核心思想是:当一个类加载器需要加载某个类时,它首先会将这个请求委托给父类加载器去执行,如果父类加载器还存在其父类加载器,就继续向上委托,直到顶层的启动类加载器(Bootstrap ClassLoader)。如果父类加载器能够完成类加载任务,就成功返回;如果父类加载器无法完成加载任务,子类加载器才会尝试自己去加载。
二、类加载器层级结构
在Java中,类加载器通常形成一个树形层级结构,主要包括以下几类:
- 启动类加载器(Bootstrap ClassLoader):最顶层的类加载器,由C++实现,负责加载Java的核心类库,如
rt.jar、resources.jar等,存放在%JRE_HOME%\lib目录下的类。 - 扩展类加载器(Extension ClassLoader):由Java代码实现,继承自
URLClassLoader,负责加载Java的扩展类库,存放在%JRE_HOME%\lib\ext目录下的类。 - 应用程序类加载器(Application ClassLoader):也由Java代码实现,继承自
URLClassLoader,是ClassLoader.getSystemClassLoader()的默认返回值,负责加载应用程序classpath路径下的类。 - 自定义类加载器(Custom ClassLoader):用户自定义的类加载器,继承自
java.lang.ClassLoader,用于加载用户自定义的类或特定位置的类。
三、工作流程
- 当某个类加载器收到类加载请求时,首先不会自己尝试加载这个类,而是将请求委托给父类加载器。
- 父类加载器接收到请求后,同样会先委托给它的父类加载器,如此向上传递,直到到达启动类加载器。
- 启动类加载器检查是否能加载该类:
- 如果能加载,就将类加载到JVM中并返回。
- 如果不能加载,就将请求返回给子类加载器,由子类加载器尝试加载。
- 扩展类加载器接收到请求后,重复上述过程,检查是否能加载该类:
- 能加载则返回。
- 不能加载则返回给应用程序类加载器。
- 应用程序类加载器接收到请求后,检查是否能加载该类:
- 能加载则返回。
- 不能加载则返回给自定义类加载器(如果有的话)。
- 如果所有父类加载器都无法加载该类,则由当前类加载器尝试加载,如果仍然无法加载,则抛出
ClassNotFoundException异常。
四、核心作用
- 确保类的唯一性:由于ClassLoader的层级结构,使得同一个类只会被加载一次,避免了类的重复加载。例如,Java核心类库中的类只会被启动类加载器加载,保证了这些类在JVM中的唯一性。
- 保证Java核心类库的安全性:核心类库由启动类加载器加载,避免了用户自定义的类对核心类库的替换,确保了Java程序的安全性和稳定性。
- 实现类的隔离性:不同的类加载器可以加载相同名称的类,这些类在JVM中是相互隔离的,提高了程序的可扩展性和灵活性。
五、源码解析
在Java中,ClassLoader类的loadClass方法实现了双亲委派机制,其核心代码如下:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |
六、打破双亲委派机制的场景
虽然双亲委派机制是Java类加载的核心机制,但在某些情况下需要打破该机制,常见的场景包括:
- JNDI服务:JNDI需要加载由应用程序提供的类,而这些类位于应用程序的classpath中,由应用程序类加载器加载。但JNDI的实现位于JDK中,由启动类加载器加载,启动类加载器无法加载应用程序类加载器中的类,因此需要打破双亲委派机制。
- OSGi框架:OSGi是一个动态模块化系统,每个模块(Bundle)都有自己的类加载器,模块之间需要相互通信,需要打破双亲委派机制来实现模块间的类共享。
- 热部署:热部署需要在不重启应用程序的情况下动态加载新的类,需要打破双亲委派机制来实现类的重新加载。
七、打破双亲委派机制的实现方式
打破双亲委派机制的核心是重写ClassLoader的loadClass方法,不再遵循双亲委派的顺序,而是先尝试自己加载类,再委托给父类加载器。例如,在JNDI中,使用了ThreadContextClassLoader来实现打破双亲委派机制,ThreadContextClassLoader可以通过Thread.currentThread().setContextClassLoader(ClassLoader cl)方法设置,在需要加载类时,使用Thread.currentThread().getContextClassLoader().loadClass(name)来加载类,从而实现由应用程序类加载器来加载类,而不是由启动类加载器来加载。
八、总结
双亲委派机制是Java类加载的核心机制,它保证了类的唯一性、安全性和隔离性。在理解双亲委派机制的基础上,我们也需要了解打破双亲委派机制的场景和实现方式,以便在开发中更好地应用类加载器。
评论



