我是靠谱客的博主 发嗲树叶,最近开发中收集的这篇文章主要介绍URLClassLoader详解URLClassLoader详解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

URLClassLoader详解

ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见。理解ClassLoader的加载机制,也有利于我们编写出更高效的代码。ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了。但是,jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态加载。想想也是的,一次性加载那么多jar包那么多class,那内存不崩溃。本文的目的也是学习ClassLoader这种加载机制。。

  • java类加载机制原理
  • 双亲加载机制的优劣

java类加载机制

classloader结构


ClassLoader结构

java中内置了很多类加载器,本文只讨论几个核心类加载器:

ClassLoader:所有类加载器的基类,它是抽象的,定义了类加载最核心的操作。所有继承与classloader的加载器,都会优先判断是否被父类加载器加载过,防止多次加载,防止加载冲突。。。

protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//锁,防止多次加载,所以jvm启动巨慢
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;
}
}

jdk 1.7为了提供并行加载class,提供ClassLoader.ParallelLoaders内部类,用来封装一组并行能力的加载器类型。这个一般是用不到的,有兴趣可以先看一下。但是需要知道ClassLoader是支持并行加载的。


private static class ParallelLoaders1

Bootstrap classLoader:位于java.lang.classload,所有的classload都要经过这个classload判断是否已经被加载过,采用native code实现,是JVM的一部分,主要加载JVM自身工作需要的类,如java.lang._、java.uti._等; 这些类位于$JAVA_HOME/jre/lib/rt.jar。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。


/**
* Returns a class loaded by the bootstrap class loader;
* or return null if not found.
*/
private Class<?> findBootstrapClassOrNull(String name)
{
if (!checkName(name)) return null;
return findBootstrapClass(name);
}
// return null if not found
private native Class<?> findBootstrapClass(String name);

SecureClassLoader:继承自ClassLoader,添加了关联类源码、关联系统policy权限等支持。


public class SecureClassLoader extends ClassLoader1

URLClassLoader:继承自SecureClassLoader,支持从jar文件和文件夹中获取class,继承于classload,加载时首先去classload里判断是否由bootstrap classload加载过,1.7 新增实现closeable接口,实现在try 中自动释放资源,但扑捉不了.close()异常

public class URLClassLoader extends SecureClassLoader implements Closeable1

ExtClassLoader:扩展类加载器,继承自URLClassLoader继承于urlclassload,扩展的class loader,加载位于$JAVA_HOME/jre/lib/ext目录下的扩展jar。查看源码可知其查找范围为System.getProperty(“java.ext.dirs”)。

public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
//System.getProperty("java.ext.dirs");
//在项目启动时就加载所有的ext.dirs目录下的文件,并将其初始化
final File[] var0 = getExtDirs();
try {
//AccessController.doPrivileged特权,让程序突破当前域权限限制,临时扩大访问权限
return (Launcher.ExtClassLoader)AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
public Launcher.ExtClassLoader run() throws IOException {
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
MetaIndex.registerDirectory(var0[var2]);
}
return new Launcher.ExtClassLoader(var0);
}
});
} catch (PrivilegedActionException var2) {
throw (IOException)var2.getException();
}
}

ExtClassLoader 比较有意思的是,他使用的是顶级类(classloader)的loadclass方法,并没有重写,而且他的父亲加载器是null。。 。

public ExtClassLoader(File[] var1) throws IOException {
//parents is null
super(getExtURLs(var1), (ClassLoader)null, Launcher.factory);
SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
}

AppClassLoader:应用类加载器,继承自URLClassLoader,也叫系统类加载器(ClassLoader.getSystemClassLoader()可得到它),它负载加载应用的classpath下的类,查找范围System.getProperty(“java.class.path”),通过-cp或-classpath指定的类都会被其加载,没有完全遵循双亲委派模型的,它重的是loadClass方法


public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = var1.lastIndexOf(46);
if (var3 != -1) {
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
var4.checkPackageAccess(var1.substring(0, var3));
}
}
//ucp是SharedSecrets获取的Java栈帧中存储的类信息
if (this.ucp.knownToNotExist(var1)) {
//顶级类classloader加载的信息
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
//link过程,Class载入必须link,link指的是把单一的Class加入到有继承关系的类树中,不link一切都无从谈起了
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
return super.loadClass(var1, var2);
}
}

Launcher:java程序入口,负责实例化相关class,ExtClassLoader和AppClassLoader都是其内部实现类。。。

首先获取bootClassPath 的位置信息,交付于父类Classloader去加载位于$JAVA_HOME/jre/lib/rt.jar 的类

private static String bootClassPath = System.getProperty("sun.boot.class.path");
public static URLClassPath getBootstrapClassPath() {
return Launcher.BootClassPathHolder.bcp;
}

实例化相关ExtClassLoader和AppClassLoader,单线程运行,内部加载会对class文件加锁(所以启动慢的原因??)


public Launcher() {
Launcher.ExtClassLoader var1;
try {
//实例化ExtClassLoader,
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
//实例化AppClassLoader,并把ExtClassLoader置为父类
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
//为线程设置上下文加载器,防止线程多次加载类
Thread.currentThread().setContextClassLoader(this.loader);
//加载安全管理
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
;
} catch (InstantiationException var6) {
;
} catch (ClassNotFoundException var7) {
;
} catch (ClassCastException var8) {
;
}
} else {
var3 = new SecurityManager();
}
if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}

ClassLoader运行结构

主要基于 双亲加载机制

classload运行结构

双亲加载机制:主要体现在ClassLoader的loadClass()方法中,思路很简单:先检查是否已经被加载过,若没有加载则调用父类加载器的loadClass()方法,若父类加载器为空则默认使用启动类加载器作为父类加载器。如果父类加载器加载失败,抛出ClassNotFoundException异常后,调用自己的findClass()方法进行加载。

双亲与判断等于:一般自定义的Class Loader可以从java.lang.ClassLoader继承,不同classloader加载相同的类,他们在内存也不是相等的,即它们不能互相转换,会直接抛异常。java.lang.ClassLoader的核心加载方法是loadClass方法


Class
clazz = null;
ClassLoader classLoader;
try {
classLoader =
new SpecialClassLoader ();
clazz = classLoader.loadClass("Hello");
System.out.println(clazz);
System.out.println(clazz.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class helloClazz;
helloClazz = Hello.class;
System.out.println("helloClazz:" + helloClazz);
System.out.println(helloClazz.getClassLoader());
System.out.println(helloClazz == clazz);
System.out.println(helloClazz.equals(clazz));

运行结果:

loadClass:Hello

specialLoadClass:test/Hello.class

loadClass:java.lang.Object

—resolveClass–

class com.test.javatechnology.classloader.test.Hello

com.test.javatechnology.classloader.SpecialClassLoader@106d69c

helloClazz:class com.test.javatechnology.classloader.test.Hello

sun.misc.Launcher$AppClassLoader@e2f2a

false

false

最后

以上就是发嗲树叶为你收集整理的URLClassLoader详解URLClassLoader详解的全部内容,希望文章能够帮你解决URLClassLoader详解URLClassLoader详解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部