类加载器
类加载器父类并不是继承的关系,而是委派关系,是在创建的时候传入其父类。
Launcher
Launcher类是java的入口,在启动java应用的时候会首先创建Launcher类,由BootStrapClassLoader负责加载。
/**
* BootStrapClassLoader会加载Launcher类;
* 可以说 ExtClassLoader、AppClassLoader 是由BootStrapClassLoader加载的;
*/
public class Launcher {
// 静态属性是创建Launcher,所以会执行Launcher()构造器
private static Launcher launcher = new Launcher();
public Launcher() {
Launcher.ExtClassLoader var1;
try {
// 创建ext类加载器,父类为null(BootStrapClassLoader),ClassLoader#loadClass父类为空时调用 #findBootstrapClassOrNull
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
// 创建app类加载器,父类为刚创建的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);
。。。
}
}
BootStrapLoader
加载的内容:javahome/jre/lib下的部分jar;
ExtClassLoader
Launcher中的内部类,继承URLClassLoader -> SecureClassLoader ->ClassLoader;
加载的内容:javahome/jre/lib/ext下的部分jar
AppClassLoader
系统类加载器与应用加载器;
Launcher中的内部类,继承URLClassLoader -> SecureClassLoader ->ClassLoader;
加载的内容:
System.getProperty("java.class.path")
1. 加载 javahome/jre/lib下的jar
2. 加载 javahome/jre/lib/ext下的jar
3. 项目对应的/target/classes
4. 加载.m2下的jar包,项目引入的三方jar
#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));
}
}
// 默认是false,除非设置启动参数lookupCacheEnabled为true
if (this.ucp.knownToNotExist(var1)) {
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
return super.loadClass(var1, var2);
}
}
URLClassLoader
- 可以指定一串路径,然后再些路径下面寻找将要加载的类。可以动态加载程序外的类
- 是ExtClassLoader、AppClassLoader的父类
实际使用demo:cloud.tencent.com/developer/a…
ContentClassLoader
Thread.currentThread().getContextClassLoader()的意义: 父Classloader可以使用当前线程Thread.currentthread().getContextLoader()中指定的classloader中加载的类。颠覆了父ClassLoader不能使用子Classloader或者是其它没有直接父子关系的Classloader中加载的类这种情况。这个就是Context Class Loader的意义。
原文链接:blog.csdn.net/qbg19881206…
ClassLoader
- java类加载器的基类
#构造器
ClassLoader构造器:
// 无参构造函数默认是AppClassLoader,子类super()即可调用
protected ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
assertionLock = this;
}
}
#loadClass
/**
*
* 1. 先对className加锁,synchronized
* 2. 查看是否已经加载过
* 3. 递归调用父类#loadClass
* 4. 调用子类#findClass
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 加锁
synchronized (getClassLoadingLock(name)) {
// 查看class是否已经加载过
Class<?> c = findLoadedClass(name);
// 没加载过
if (c == null) {
long t0 = System.nanoTime();
try {
// 有父类:调用父类#loadClass,没有父类:调用BootStrap
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
// 父类未也未找到class,调用#findClass
if (c == null) {
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();
}
}
// 解析class文件,就是将符号引用替换为直接引用的过程
if (resolve) {
resolveClass(c);
}
return c;
}
}
/**
*
* 1. 不推荐使用String、Integer作为锁对象,有缓存区的存在。
* 2. 1.7之后,加锁的时候如果加载器具备并行能力,那么就不再对类加载器进行加锁,而是找到加载类文件对应的Object锁进行加锁操作。
*/
protected Object getClassLoadingLock(String className) {
// 默认使用当前类加载器做为锁对象
Object lock = this;
// 判断平行的锁Map是否存在,存在则获取className对应的锁对象
if (parallelLockMap != null) {
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}
#findClass
// 父类未加载到class时,子类再进行查找,子类未实现时抛出ClassNotFoundException异常
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
URLClassLoader#findClass
protected Class<?> findClass(final String name)
throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
// 将.替换成/,拼接.class,再进行加载
String path = name.replace('.', '/').concat(".class");
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
// 将字节码转成Class对象
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
#defineClass
将字节码转成Class对象
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain) throws ClassFormatError{
protectionDomain = preDefineClass(name, protectionDomain);
String source = defineClassSourceLocation(protectionDomain);
// 调用native方法生成class对象
Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
postDefineClass(c, protectionDomain);
return c;
}
ContentClassLoader
其它知识
-
父类没有无参构造器,子类需要在构造器中通过#super调用父类的有参数构造器
-
new子类,并不会new一个父类,只会执行父类的构造器,实例化父类的属性
比如: A是 a 与 b的父类,A中有name的属性。 创建a时,name设置为a 创建b时,name设置为b 这时候打印a.name为:a,b.name为b,并不会相互影响 -
jdk包,rt.jar是java继承类库,其中包括java、javax、sun等类包
- java:java SE的标准库,我们程序中可以调用
- javax:标准库的扩展
- sun:是sun的hotspot虚拟机中java.* 和javax.*的实现类。因为包含在rt中,所以我们也可以调用。