类加载流程图

image.png
1.创建引导类加载器(C语言实现)(bootstrapClassLoader)
2.创建JVM启动器
3.实例化启动器过程中,初始化extClassLoader、AppClassLoader。

一、JVM启动器结构预览

image.png
扩展与应用类加载器都是启动器内部类

  1. package sun.misc;
  2. public class Launcher {
  3. private static URLStreamHandlerFactory factory = new Launcher.Factory();
  4. //加载是实例化
  5. private static Launcher launcher = new Launcher();
  6. private static String bootClassPath = System.getProperty("sun.boot.class.path");
  7. private ClassLoader loader;
  8. private static URLStreamHandler fileHandler;
  9. public static Launcher getLauncher() {
  10. return launcher;
  11. }
  12. public Launcher() {
  13. Launcher.ExtClassLoader var1;
  14. try {
  15. //获取扩展类加载器对象。(扩展类加载器,是Launcher的一个内部类)
  16. var1 = Launcher.ExtClassLoader.getExtClassLoader();
  17. } catch (IOException var10) {
  18. throw new InternalError("Could not create extension class loader", var10);
  19. }
  20. try {
  21. //扩展类加载器作为入参,最终为AppClassLoader中parent属性赋值,即标识父加载器
  22. //(应用类加载器,是Launcher的一个内部类)
  23. this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
  24. } catch (IOException var9) {
  25. throw new InternalError("Could not create application class loader", var9);
  26. }
  27. Thread.currentThread().setContextClassLoader(this.loader);
  28. String var2 = System.getProperty("java.security.manager");
  29. if (var2 != null) {
  30. SecurityManager var3 = null;
  31. if (!"".equals(var2) && !"default".equals(var2)) {
  32. try {
  33. var3 = (SecurityManager) this.loader.loadClass(var2).newInstance();
  34. } catch (IllegalAccessException var5) {
  35. ;
  36. } catch (InstantiationException var6) {
  37. ;
  38. } catch (ClassNotFoundException var7) {
  39. ;
  40. } catch (ClassCastException var8) {
  41. ;
  42. }
  43. } else {
  44. var3 = new SecurityManager();
  45. }
  46. if (var3 == null) {
  47. throw new InternalError("Could not create SecurityManager: " + var2);
  48. }
  49. System.setSecurityManager(var3);
  50. }
  51. }
  52. /***
  53. *获取应用类加载器appClassLoader
  54. **/
  55. public ClassLoader getClassLoader() {
  56. return this.loader;
  57. }
  58. public static URLClassPath getBootstrapClassPath() {
  59. return Launcher.BootClassPathHolder.bcp;
  60. }
  61. private static File[] getClassPath(String var0) {
  62. File[] var1;
  63. if (var0 != null) {
  64. int var2 = 0;
  65. int var3 = 1;
  66. boolean var4 = false;
  67. int var5;
  68. int var7;
  69. for (var5 = 0; (var7 = var0.indexOf(File.pathSeparator, var5)) != -1; var5 = var7 + 1) {
  70. ++var3;
  71. }
  72. var1 = new File[var3];
  73. var4 = false;
  74. for (var5 = 0; (var7 = var0.indexOf(File.pathSeparator, var5)) != -1; var5 = var7 + 1) {
  75. if (var7 - var5 > 0) {
  76. var1[var2++] = new File(var0.substring(var5, var7));
  77. } else {
  78. var1[var2++] = new File(".");
  79. }
  80. }
  81. if (var5 < var0.length()) {
  82. var1[var2++] = new File(var0.substring(var5));
  83. } else {
  84. var1[var2++] = new File(".");
  85. }
  86. if (var2 != var3) {
  87. File[] var6 = new File[var2];
  88. System.arraycopy(var1, 0, var6, 0, var2);
  89. var1 = var6;
  90. }
  91. } else {
  92. var1 = new File[0];
  93. }
  94. return var1;
  95. }
  96. static class AppClassLoader extends URLClassLoader {
  97. final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
  98. public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
  99. final String var1 = System.getProperty("java.class.path");
  100. final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
  101. return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
  102. public Launcher.AppClassLoader run() {
  103. URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
  104. return new Launcher.AppClassLoader(var1x, var0);
  105. }
  106. });
  107. }
  108. AppClassLoader(URL[] var1, ClassLoader var2) {
  109. super(var1, var2, Launcher.factory);
  110. this.ucp.initLookupCache(this);
  111. }
  112. public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
  113. int var3 = var1.lastIndexOf(46);
  114. if (var3 != -1) {
  115. SecurityManager var4 = System.getSecurityManager();
  116. if (var4 != null) {
  117. var4.checkPackageAccess(var1.substring(0, var3));
  118. }
  119. }
  120. if (this.ucp.knownToNotExist(var1)) {
  121. Class var5 = this.findLoadedClass(var1);
  122. if (var5 != null) {
  123. if (var2) {
  124. this.resolveClass(var5);
  125. }
  126. return var5;
  127. } else {
  128. throw new ClassNotFoundException(var1);
  129. }
  130. } else {
  131. return super.loadClass(var1, var2);
  132. }
  133. }
  134. protected PermissionCollection getPermissions(CodeSource var1) {
  135. PermissionCollection var2 = super.getPermissions(var1);
  136. var2.add(new RuntimePermission("exitVM"));
  137. return var2;
  138. }
  139. private void appendToClassPathForInstrumentation(String var1) {
  140. assert Thread.holdsLock(this);
  141. super.addURL(Launcher.getFileURL(new File(var1)));
  142. }
  143. private static AccessControlContext getContext(File[] var0) throws MalformedURLException {
  144. PathPermissions var1 = new PathPermissions(var0);
  145. ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[]) null), var1);
  146. AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
  147. return var3;
  148. }
  149. static {
  150. ClassLoader.registerAsParallelCapable();
  151. }
  152. }
  153. private static class BootClassPathHolder {
  154. static final URLClassPath bcp;
  155. private BootClassPathHolder() {
  156. }
  157. static {
  158. URL[] var0;
  159. if (Launcher.bootClassPath != null) {
  160. var0 = (URL[]) AccessController.doPrivileged(new PrivilegedAction<URL[]>() {
  161. public URL[] run() {
  162. File[] var1 = Launcher.getClassPath(Launcher.bootClassPath);
  163. int var2 = var1.length;
  164. HashSet var3 = new HashSet();
  165. for (int var4 = 0; var4 < var2; ++var4) {
  166. File var5 = var1[var4];
  167. if (!var5.isDirectory()) {
  168. var5 = var5.getParentFile();
  169. }
  170. if (var5 != null && var3.add(var5)) {
  171. MetaIndex.registerDirectory(var5);
  172. }
  173. }
  174. return Launcher.pathToURLs(var1);
  175. }
  176. });
  177. } else {
  178. var0 = new URL[0];
  179. }
  180. bcp = new URLClassPath(var0, Launcher.factory, (AccessControlContext) null);
  181. bcp.initLookupCache((ClassLoader) null);
  182. }
  183. }
  184. static class ExtClassLoader extends URLClassLoader {
  185. public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
  186. final File[] var0 = getExtDirs();
  187. try {
  188. return (Launcher.ExtClassLoader) AccessController.doPrivileged(new PrivilegedExceptionAction<Launcher.ExtClassLoader>() {
  189. public Launcher.ExtClassLoader run() throws IOException {
  190. int var1 = var0.length;
  191. for (int var2 = 0; var2 < var1; ++var2) {
  192. MetaIndex.registerDirectory(var0[var2]);
  193. }
  194. return new Launcher.ExtClassLoader(var0);
  195. }
  196. });
  197. } catch (PrivilegedActionException var2) {
  198. throw (IOException) var2.getException();
  199. }
  200. }
  201. void addExtURL(URL var1) {
  202. super.addURL(var1);
  203. }
  204. //因为bootstrapClassLoader是C++实现,没有具体java对象,故ExtClassLoader对象parent属性为空。
  205. public ExtClassLoader(File[] var1) throws IOException {
  206. super(getExtURLs(var1), (ClassLoader) null, Launcher.factory);
  207. SharedSecrets.getJavaNetAccess().getURLClassPath(this).initLookupCache(this);
  208. }
  209. private static File[] getExtDirs() {
  210. String var0 = System.getProperty("java.ext.dirs");
  211. File[] var1;
  212. if (var0 != null) {
  213. StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
  214. int var3 = var2.countTokens();
  215. var1 = new File[var3];
  216. for (int var4 = 0; var4 < var3; ++var4) {
  217. var1[var4] = new File(var2.nextToken());
  218. }
  219. } else {
  220. var1 = new File[0];
  221. }
  222. return var1;
  223. }
  224. private static URL[] getExtURLs(File[] var0) throws IOException {
  225. Vector var1 = new Vector();
  226. for (int var2 = 0; var2 < var0.length; ++var2) {
  227. String[] var3 = var0[var2].list();
  228. if (var3 != null) {
  229. for (int var4 = 0; var4 < var3.length; ++var4) {
  230. if (!var3[var4].equals("meta-index")) {
  231. File var5 = new File(var0[var2], var3[var4]);
  232. var1.add(Launcher.getFileURL(var5));
  233. }
  234. }
  235. }
  236. }
  237. URL[] var6 = new URL[var1.size()];
  238. var1.copyInto(var6);
  239. return var6;
  240. }
  241. public String findLibrary(String var1) {
  242. var1 = System.mapLibraryName(var1);
  243. URL[] var2 = super.getURLs();
  244. File var3 = null;
  245. for (int var4 = 0; var4 < var2.length; ++var4) {
  246. URI var5;
  247. try {
  248. var5 = var2[var4].toURI();
  249. } catch (URISyntaxException var9) {
  250. continue;
  251. }
  252. File var6 = (new File(var5)).getParentFile();
  253. if (var6 != null && !var6.equals(var3)) {
  254. String var7 = VM.getSavedProperty("os.arch");
  255. File var8;
  256. if (var7 != null) {
  257. var8 = new File(new File(var6, var7), var1);
  258. if (var8.exists()) {
  259. return var8.getAbsolutePath();
  260. }
  261. }
  262. var8 = new File(var6, var1);
  263. if (var8.exists()) {
  264. return var8.getAbsolutePath();
  265. }
  266. }
  267. var3 = var6;
  268. }
  269. return null;
  270. }
  271. private static AccessControlContext getContext(File[] var0) throws IOException {
  272. PathPermissions var1 = new PathPermissions(var0);
  273. ProtectionDomain var2 = new ProtectionDomain(new CodeSource(var1.getCodeBase(), (Certificate[]) null), var1);
  274. AccessControlContext var3 = new AccessControlContext(new ProtectionDomain[]{var2});
  275. return var3;
  276. }
  277. static {
  278. ClassLoader.registerAsParallelCapable();
  279. }
  280. }
  281. private static class Factory implements URLStreamHandlerFactory {
  282. private static String PREFIX = "sun.net.www.protocol";
  283. private Factory() {
  284. }
  285. public URLStreamHandler createURLStreamHandler(String var1) {
  286. String var2 = PREFIX + "." + var1 + ".Handler";
  287. try {
  288. Class var3 = Class.forName(var2);
  289. return (URLStreamHandler) var3.newInstance();
  290. } catch (ReflectiveOperationException var4) {
  291. throw new InternalError("could not load " + var1 + "system protocol handler", var4);
  292. }
  293. }
  294. }
  295. }

二、自定义类加载器

打破双亲委派,改写ClassLoader中查找父类加载器的逻辑即可,避免加载自定义类时,被委派给应用类加载器。(注意jdk核心代码需要,仍然使用双亲委派,不能使用自定义类加载器加载jdk核心包)