- 双亲委派机制的过程如何?
类加载器会首先代理给父类加载器尝试加载某个类。这就意味着真正完成类的加载工作的类加载器和启动这个加载过程的类加载器,有可能不是同一个。真正完成类的加载工作是通过调用 defineClass来实现的;而启动类的加载过程是通过调用 loadClass来实现的。前者称为一个类的定义加载器(defining loader),后者称为初始加载器(initiating loader)。在 Java 虚拟机判断两个类是否相同的时候,使用的是类的定义加载器。也就是说,哪个类加载器启动类的加载过程并不重要,重要的是最终定义这个类的加载器。两种类加载器的关联之处在于:一个类的定义加载器是它引用的其它类的初始加载器。如类 com.example.Outer引用了类 com.example.Inner,则由类 com.example.Outer的定义加载器负责启动类 com.example.Inner的加载过程。 - 双亲委派机制中loadClass()、findClass()和defineClass()分别是干啥的?
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
根据ClassLoader类的这段代码,调用每个类加载器的loadClass()都会先从缓存中寻找该class,如果找不到,再委托给父类加载,若加载不到就调用findClass()。findClass()方法会在它的根目录搜索.class文件,若找到再调用defineClass()方法转换成class实例并返回。所以调用关系是loadClass()->findClass()->defineClass(),抛出的异常也有所不同,loadClass()抛出ClassNotFoundException,而findClass()抛出NoClassDefFoundError异常。
-
线程上下文类加载器是什么?
-
tomcat的类加载器是如何加载的?
该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。每个应用字节的java类文件和使用的jar包,分别放在WEB-INF/classed和WEB-INF/lib下 -
OSGi为何要打破双亲委派模式?
OSGi 中的每个模块(bundle)都包含 Java 包和类。模块可以声明它所依赖的需要导入(import)的其它模块的 Java 包和类(通过 Import-Package),也可以声明导出(export)自己的包和类,供其它模块使用(通过 Export-Package)。也就是说需要能够隐藏和共享一个模块中的某些 Java 包和类。这是通过 OSGi 特有的类加载器机制来实现的。OSGi 中的每个模块都有对应的一个类加载器。它负责加载模块自己包含的 Java 包和类。当它需要加载 Java 核心库的类时(以 java开头的包和类),它会代理给父类加载器(通常是启动类加载器)来完成。当它需要加载所导入的 Java 类时,它会代理给导出此 Java 类的模块来完成加载。模块也可以显式的声明某些 Java 包和类,必须由父类加载器来加载。只需要设置系统属性 org.osgi.framework.bootdelegation的值即可。 -
SPI(Service Provider Interfact)为何要打破双亲委派模式?
因为SPI的接口是java核心类库的一部分,是由引导类加载器(BootstrapClassLoader)加载,而它的实现类并不在引导类加载器的加载路径,而引导类加载器已经是根类加载器了,无法再委托给父类加载器了,所以通过双亲委派机制是加载不到其实现类的。 -
当前类加载器和上下文加载器如何选择?
https://www.ibm.com/developerworks/cn/java/j-lo-classloader/