本文共 6970 字,大约阅读时间需要 23 分钟。
ClassLoader是Java的核心组件,主要工作在Class装载的加载阶段。所有的Class都是由ClassLoader进行加载的,ClassLoader 负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接、初始化等操作。
作用:C++编写而成, 它是最顶层的类加载器,已经内嵌到JVM中了。在JVM启动时会初始化该ClassLoader,它主要用来读取Java的核心类库JRE/lib/rt.jar中所有的class文件,这个jar文件中包含了java规范定义的所有接口及实现。
(1)作用
Java编写,它是用来加载Java的扩展类库javax.*,如读取JRE/lib/ext/*.jar中的包等(这里要注意,有些版本的是没有ext这个目录的)。
(2)源码-》查看加载文件路径:
static class ExtClassLoader extends URLClassLoader {…private static File[] getExtDirs() { String var0 = System.getProperty("java.ext.dirs"); File[] var1; if (var0 != null) { StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator); int var3 = var2.countTokens(); var1 = new File[var3]; for(int var4 = 0; var4 < var3; ++var4) { var1[var4] = new File(var2.nextToken()); } } else { var1 = new File[0]; } return var1;}…}
Idea中查看主要类目录
public class test { public static void main(String[] args) { System.out.println(System.getProperty("java.ext.dirs")); }}
结果:
C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext(1)作用
Java编写,它是用来读取CLASSPATH下指定的所有jar包或目录的类文件,一般情况下这个就是程序中默认的类加载器。
(2)源码-》查看加载文件路径:
static class AppClassLoader extends URLClassLoader {public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException { final String var1 = System.getProperty("java.class.path"); final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction() { public Launcher.AppClassLoader run() { URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2); return new Launcher.AppClassLoader(var1x, var0); } });}}
文件加载路径为:System.getProperty("java.class.path")
package com.spring.ioc.c5;public class test { public static void main(String[] args) { System.out.println(System.getProperty("java.class.path")); }}
路径:主要是...\javabase\target\classes下面的编译好的包和类
C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program…
E:\02LocalProject\javabase\target\classes; ….定制化开发,下面可以代码实现
(1)作用:可以避免同样的字节码加载多次到内存中,一次加载到内存中,如果后续需要,则直接取出使用,不需要,重复加载第二次。
(2)自下而上,检测是否已经加载,如果加载过,则直接调用该class;如果没有加载过,则采用自下而上重新加载。
(3)自上而下,如果寻找对应class文件,有则加载
(4)源码
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加载类的入口,此方法负责加载指定名字的类。ClassLoader的实现方法为先从已经加载的类中寻找,如没有则继续从父ClassLoader中寻找,如仍然没找到,则从BootstrapClassLoader中寻找,最后再调用findClass方法来寻找。
作用:查找二进制class文件,并且加载返回一个对象
源码:protected Class findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name);}
作用:读取字节流,返回类对象
源码:protected final Class defineClass(String name, byte[] b, int off, int len) throws ClassFormatError{ return defineClass(name, b, off, len, null);}
package com.spring.ioc.c5;public class InputClass { static { System.out.println("Hello World! I am InputClass"); }}
使用idea的终端Terminal在当前目录下编译为InputClass.class文件
…\javabase\src\main\java\com\spring\ioc\c5>javac InputClass.java 生成…\javabase\src\main\java\com\spring\ioc\c5\InputClass.classpackage com.spring.ioc.c5;import java.io.*;public class ClassLoaderDIY extends ClassLoader{ private String path; //加载class的路径(不包含文件名称) private String classLoaderName; //加载的class名称 public ClassLoaderDIY(String path, String classLoaderName) { this.path = path; this.classLoaderName = classLoaderName; } //寻找类文件,并且以二进制数组方式加载进来 @Override protected Class findClass(String name) throws ClassNotFoundException { byte[] b=loadClassData(name); return defineClass(name,b,0,b.length); } //用于加载类文件 private byte[] loadClassData(String name) { name=path+name+".class"; //即:路径+名称 InputStream in=null; ByteArrayOutputStream out=null; try { in=new FileInputStream(new File(name)); out=new ByteArrayOutputStream(); int i=0; while ((i=in.read())!=-1){ out.write(i); } } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } return out.toByteArray(); }}
package com.spring.ioc.c5;public class ClassLoadTest { public static void main(String[] args) { ClassLoaderDIY classLoaderDIY=new ClassLoaderDIY("src\\main\\java\\com\\spring\\ioc\\c5\\","FirstClassLoader"); Class c= null; try { c = classLoaderDIY.loadClass("com.spring.ioc.c5.InputClass"); System.out.println(c.getClassLoader()); c.newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { e.printStackTrace(); } }}
注意:因为加载类,在com.spring.ioc.c5下面,所以,加载类时需要加载指定包目录:com.spring.ioc.c5.InputClass,具体参考:
加载成功
sun.misc.Launcher$AppClassLoader@18b4aac2
Hello World! I am InputClass1. https://blog.csdn.net/tonytfjing/article/details/47212291