这次重新阅读了一下sun.misc.Launcher这个类的源码,这里总结一下。
1package sun.misc;
2
3import java.io.File;
4import java.io.IOException;
5import java.io.FilePermission;
6import java.net.URL;
7import java.net.URLClassLoader;
8import java.net.MalformedURLException;
9import java.net.URLStreamHandler;
10import java.net.URLStreamHandlerFactory;
11import java.util.HashSet;
12import java.util.StringTokenizer;
13import java.util.Set;
14import java.util.Vector;
15import java.security.AccessController;
16import java.security.PrivilegedAction;
17import java.security.PrivilegedExceptionAction;
18import java.security.AccessControlContext;
19import java.security.PermissionCollection;
20import java.security.Permissions;
21import java.security.Permission;
22import java.security.ProtectionDomain;
23import java.security.CodeSource;
24import sun.security.util.SecurityConstants;
25import sun.net.www.ParseUtil;
26
27/**
28 * This class is used by the system to launch the main application.
29Launcher */
30public class Launcher {
31 private static URLStreamHandlerFactory factory = new Factory();
32 private static Launcher launcher = new Launcher();
33 private static String bootClassPath =
34 System.getProperty("sun.boot.class.path");
35
36 public static Launcher getLauncher() {
37 return launcher;
38 }
39
40 private ClassLoader loader;
41
42 public Launcher() {
43 // Create the extension class loader
44 ClassLoader extcl;
45 try {
46 extcl = ExtClassLoader.getExtClassLoader();
47 } catch (IOException e) {
48 throw new InternalError(
49 "Could not create extension class loader", e);
50 }
51
52 // Now create the class loader to use to launch the application
53 try {
54 loader = AppClassLoader.getAppClassLoader(extcl);
55 } catch (IOException e) {
56 throw new InternalError(
57 "Could not create application class loader", e);
58 }
59
60 // Also set the context class loader for the primordial thread.
61 Thread.currentThread().setContextClassLoader(loader);
62
63 // Finally, install a security manager if requested
64 String s = System.getProperty("java.security.manager");
65 if (s != null) {
66 SecurityManager sm = null;
67 if ("".equals(s) || "default".equals(s)) {
68 sm = new java.lang.SecurityManager();
69 } else {
70 try {
71 sm = (SecurityManager)loader.loadClass(s).newInstance();
72 } catch (IllegalAccessException e) {
73 } catch (InstantiationException e) {
74 } catch (ClassNotFoundException e) {
75 } catch (ClassCastException e) {
76 }
77 }
78 if (sm != null) {
79 System.setSecurityManager(sm);
80 } else {
81 throw new InternalError(
82 "Could not create SecurityManager: " + s);
83 }
84 }
85 }
86
87 /*
88 * Returns the class loader used to launch the main application.
89 */
90 public ClassLoader getClassLoader() {
91 return loader;
92 }
93
94 /*
95 * The class loader used for loading installed extensions.
96 */
97 static class ExtClassLoader extends URLClassLoader {
98
99 static {
100 ClassLoader.registerAsParallelCapable();
101 }
102
103 /**
104 * create an ExtClassLoader. The ExtClassLoader is created
105 * within a context that limits which files it can read
106 */
107 public static ExtClassLoader getExtClassLoader() throws IOException
108 {
109 final File[] dirs = getExtDirs();
110
111 try {
112 // Prior implementations of this doPrivileged() block supplied
113 // aa synthesized ACC via a call to the private method
114 // ExtClassLoader.getContext().
115
116 return AccessController.doPrivileged(
117 new PrivilegedExceptionAction<ExtClassLoader>() {
118 public ExtClassLoader run() throws IOException {
119 int len = dirs.length;
120 for (int i = 0; i < len; i++) {
121 MetaIndex.registerDirectory(dirs[i]);
122 }
123 return new ExtClassLoader(dirs);
124 }
125 });
126 } catch (java.security.PrivilegedActionException e) {
127 throw (IOException) e.getException();
128 }
129 }
130
131 void addExtURL(URL url) {
132 super.addURL(url);
133 }
134
135 /*
136 * Creates a new ExtClassLoader for the specified directories.
137 */
138 public ExtClassLoader(File[] dirs) throws IOException {
139 super(getExtURLs(dirs), null, factory);
140 SharedSecrets.getJavaNetAccess().
141 getURLClassPath(this).initLookupCache(this);
142 }
143
144 private static File[] getExtDirs() {
145 String s = System.getProperty("java.ext.dirs");
146 File[] dirs;
147 if (s != null) {
148 StringTokenizer st =
149 new StringTokenizer(s, File.pathSeparator);
150 int count = st.countTokens();
151 dirs = new File[count];
152 for (int i = 0; i < count; i++) {
153 dirs[i] = new File(st.nextToken());
154 }
155 } else {
156 dirs = new File[0];
157 }
158 return dirs;
159 }
160
161 private static URL[] getExtURLs(File[] dirs) throws IOException {
162 Vector<URL> urls = new Vector<URL>();
163 for (int i = 0; i < dirs.length; i++) {
164 String[] files = dirs[i].list();
165 if (files != null) {
166 for (int j = 0; j < files.length; j++) {
167 if (!files[j].equals("meta-index")) {
168 File f = new File(dirs[i], files[j]);
169 urls.add(getFileURL(f));
170 }
171 }
172 }
173 }
174 URL[] ua = new URL[urls.size()];
175 urls.copyInto(ua);
176 return ua;
177 }
178
179 /*
180 * Searches the installed extension directories for the specified
181 * library name. For each extension directory, we first look for
182 * the native library in the subdirectory whose name is the value
183 * of the system property <code>os.arch</code>. Failing that, we
184 * look in the extension directory itself.
185 */
186 public String findLibrary(String name) {
187 name = System.mapLibraryName(name);
188 URL[] urls = super.getURLs();
189 File prevDir = null;
190 for (int i = 0; i < urls.length; i++) {
191 // Get the ext directory from the URL
192 File dir = new File(urls[i].getPath()).getParentFile();
193 if (dir != null && !dir.equals(prevDir)) {
194 // Look in architecture-specific subdirectory first
195 // Read from the saved system properties to avoid deadlock
196 String arch = VM.getSavedProperty("os.arch");
197 if (arch != null) {
198 File file = new File(new File(dir, arch), name);
199 if (file.exists()) {
200 return file.getAbsolutePath();
201 }
202 }
203 // Then check the extension directory
204 File file = new File(dir, name);
205 if (file.exists()) {
206 return file.getAbsolutePath();
207 }
208 }
209 prevDir = dir;
210 }
211 return null;
212 }
213
214 private static AccessControlContext getContext(File[] dirs)
215 throws IOException
216 {
217 PathPermissions perms =
218 new PathPermissions(dirs);
219
220 ProtectionDomain domain = new ProtectionDomain(
221 new CodeSource(perms.getCodeBase(),
222 (java.security.cert.Certificate[]) null),
223 perms);
224
225 AccessControlContext acc =
226 new AccessControlContext(new ProtectionDomain[] { domain });
227
228 return acc;
229 }
230 }
231
232 /**
233 * The class loader used for loading from java.class.path.
234 * runs in a restricted security context.
235 */
236 static class AppClassLoader extends URLClassLoader {
237
238 static {
239 ClassLoader.registerAsParallelCapable();
240 }
241
242 public static ClassLoader getAppClassLoader(final ClassLoader extcl)
243 throws IOException
244 {
245 final String s = System.getProperty("java.class.path");
246 final File[] path = (s == null) ? new File[0] : getClassPath(s);
247
248 // Note: on bugid 4256530
249 // Prior implementations of this doPrivileged() block supplied
250 // a rather restrictive ACC via a call to the private method
251 // AppClassLoader.getContext(). This proved overly restrictive
252 // when loading classes. Specifically it prevent
253 // accessClassInPackage.sun.* grants from being honored.
254 //
255 return AccessController.doPrivileged(
256 new PrivilegedAction<AppClassLoader>() {
257 public AppClassLoader run() {
258 URL[] urls =
259 (s == null) ? new URL[0] : pathToURLs(path);
260 return new AppClassLoader(urls, extcl);
261 }
262 });
263 }
264
265 final URLClassPath ucp;
266
267 /*
268 * Creates a new AppClassLoader
269 */
270 AppClassLoader(URL[] urls, ClassLoader parent) {
271 super(urls, parent, factory);
272 ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
273 ucp.initLookupCache(this);
274 }
275
276 /**
277 * Override loadClass so we can checkPackageAccess.
278 */
279 public Class<?> loadClass(String name, boolean resolve)
280 throws ClassNotFoundException
281 {
282 int i = name.lastIndexOf('.');
283 if (i != -1) {
284 SecurityManager sm = System.getSecurityManager();
285 if (sm != null) {
286 sm.checkPackageAccess(name.substring(0, i));
287 }
288 }
289
290 if (ucp.knownToNotExist(name)) {
291 // The class of the given name is not found in the parent
292 // class loader as well as its local URLClassPath.
293 // Check if this class has already been defined dynamically;
294 // if so, return the loaded class; otherwise, skip the parent
295 // delegation and findClass.
296 Class<?> c = findLoadedClass(name);
297 if (c != null) {
298 if (resolve) {
299 resolveClass(c);
300 }
301 return c;
302 }
303 throw new ClassNotFoundException(name);
304 }
305
306 return (super.loadClass(name, resolve));
307 }
308
309 /**
310 * allow any classes loaded from classpath to exit the VM.
311 */
312 protected PermissionCollection getPermissions(CodeSource codesource)
313 {
314 PermissionCollection perms = super.getPermissions(codesource);
315 perms.add(new RuntimePermission("exitVM"));
316 return perms;
317 }
318
319 /**
320 * This class loader supports dynamic additions to the class path
321 * at runtime.
322 *
323 * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch
324 */
325 private void appendToClassPathForInstrumentation(String path) {
326 assert(Thread.holdsLock(this));
327
328 // addURL is a no-op if path already contains the URL
329 super.addURL( getFileURL(new File(path)) );
330 }
331
332 /**
333 * create a context that can read any directories (recursively)
334 * mentioned in the class path. In the case of a jar, it has to
335 * be the directory containing the jar, not just the jar, as jar
336 * files might refer to other jar files.
337 */
338
339 private static AccessControlContext getContext(File[] cp)
340 throws java.net.MalformedURLException
341 {
342 PathPermissions perms =
343 new PathPermissions(cp);
344
345 ProtectionDomain domain =
346 new ProtectionDomain(new CodeSource(perms.getCodeBase(),
347 (java.security.cert.Certificate[]) null),
348 perms);
349
350 AccessControlContext acc =
351 new AccessControlContext(new ProtectionDomain[] { domain });
352
353 return acc;
354 }
355 }
356
357 private static class BootClassPathHolder {
358 static final URLClassPath bcp;
359 static {
360 URL[] urls;
361 if (bootClassPath != null) {
362 urls = AccessController.doPrivileged(
363 new PrivilegedAction<URL[]>() {
364 public URL[] run() {
365 File[] classPath = getClassPath(bootClassPath);
366 int len = classPath.length;
367 Set<File> seenDirs = new HashSet<File>();
368 for (int i = 0; i < len; i++) {
369 File curEntry = classPath[i];
370 // Negative test used to properly handle
371 // nonexistent jars on boot class path
372 if (!curEntry.isDirectory()) {
373 curEntry = curEntry.getParentFile();
374 }
375 if (curEntry != null && seenDirs.add(curEntry)) {
376 MetaIndex.registerDirectory(curEntry);
377 }
378 }
379 return pathToURLs(classPath);
380 }
381 }
382 );
383 } else {
384 urls = new URL[0];
385 }
386 bcp = new URLClassPath(urls, factory);
387 bcp.initLookupCache(null);
388 }
389 }
390
391 public static URLClassPath getBootstrapClassPath() {
392 return BootClassPathHolder.bcp;
393 }
394
395 private static URL[] pathToURLs(File[] path) {
396 URL[] urls = new URL[path.length];
397 for (int i = 0; i < path.length; i++) {
398 urls[i] = getFileURL(path[i]);
399 }
400 // DEBUG
401 //for (int i = 0; i < urls.length; i++) {
402 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"');
403 //}
404 return urls;
405 }
406
407 private static File[] getClassPath(String cp) {
408 File[] path;
409 if (cp != null) {
410 int count = 0, maxCount = 1;
411 int pos = 0, lastPos = 0;
412 // Count the number of separators first
413 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
414 maxCount++;
415 lastPos = pos + 1;
416 }
417 path = new File[maxCount];
418 lastPos = pos = 0;
419 // Now scan for each path component
420 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) {
421 if (pos - lastPos > 0) {
422 path[count++] = new File(cp.substring(lastPos, pos));
423 } else {
424 // empty path component translates to "."
425 path[count++] = new File(".");
426 }
427 lastPos = pos + 1;
428 }
429 // Make sure we include the last path component
430 if (lastPos < cp.length()) {
431 path[count++] = new File(cp.substring(lastPos));
432 } else {
433 path[count++] = new File(".");
434 }
435 // Trim array to correct size
436 if (count != maxCount) {
437 File[] tmp = new File[count];
438 System.arraycopy(path, 0, tmp, 0, count);
439 path = tmp;
440 }
441 } else {
442 path = new File[0];
443 }
444 // DEBUG
445 //for (int i = 0; i < path.length; i++) {
446 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"');
447 //}
448 return path;
449 }
450
451 private static URLStreamHandler fileHandler;
452
453 static URL getFileURL(File file) {
454 try {
455 file = file.getCanonicalFile();
456 } catch (IOException e) {}
457
458 try {
459 return ParseUtil.fileToEncodedURL(file);
460 } catch (MalformedURLException e) {
461 // Should never happen since we specify the protocol...
462 throw new InternalError(e);
463 }
464 }
465
466 /*
467 * The stream handler factory for loading system protocol handlers.
468 */
469 private static class Factory implements URLStreamHandlerFactory {
470 private static String PREFIX = "sun.net.www.protocol";
471
472 public URLStreamHandler createURLStreamHandler(String protocol) {
473 String name = PREFIX + "." + protocol + ".Handler";
474 try {
475 Class<?> c = Class.forName(name);
476 return (URLStreamHandler)c.newInstance();
477 } catch (ReflectiveOperationException e) {
478 throw new InternalError("could not load " + protocol +
479 "system protocol handler", e);
480 }
481 }
482 }
483}
484
485class PathPermissions extends PermissionCollection {
486 // use serialVersionUID from JDK 1.2.2 for interoperability
487 private static final long serialVersionUID = 8133287259134945693L;
488
489 private File path[];
490 private Permissions perms;
491
492 URL codeBase;
493
494 PathPermissions(File path[])
495 {
496 this.path = path;
497 this.perms = null;
498 this.codeBase = null;
499 }
500
501 URL getCodeBase()
502 {
503 return codeBase;
504 }
505
506 public void add(java.security.Permission permission) {
507 throw new SecurityException("attempt to add a permission");
508 }
509
510 private synchronized void init()
511 {
512 if (perms != null)
513 return;
514
515 perms = new Permissions();
516
517 // this is needed to be able to create the classloader itself!
518 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
519
520 // add permission to read any "java.*" property
521 perms.add(new java.util.PropertyPermission("java.*",
522 SecurityConstants.PROPERTY_READ_ACTION));
523
524 AccessController.doPrivileged(new PrivilegedAction<Void>() {
525 public Void run() {
526 for (int i=0; i < path.length; i++) {
527 File f = path[i];
528 String path;
529 try {
530 path = f.getCanonicalPath();
531 } catch (IOException ioe) {
532 path = f.getAbsolutePath();
533 }
534 if (i == 0) {
535 codeBase = Launcher.getFileURL(new File(path));
536 }
537 if (f.isDirectory()) {
538 if (path.endsWith(File.separator)) {
539 perms.add(new FilePermission(path+"-",
540 SecurityConstants.FILE_READ_ACTION));
541 } else {
542 perms.add(new FilePermission(
543 path + File.separator+"-",
544 SecurityConstants.FILE_READ_ACTION));
545 }
546 } else {
547 int endIndex = path.lastIndexOf(File.separatorChar);
548 if (endIndex != -1) {
549 path = path.substring(0, endIndex+1) + "-";
550 perms.add(new FilePermission(path,
551 SecurityConstants.FILE_READ_ACTION));
552 } else {
553 // XXX?
554 }
555 }
556 }
557 return null;
558 }
559 });
560 }
561
562 public boolean implies(java.security.Permission permission) {
563 if (perms == null)
564 init();
565 return perms.implies(permission);
566 }
567
568 public java.util.Enumeration<Permission> elements() {
569 if (perms == null)
570 init();
571 synchronized (perms) {
572 return perms.elements();
573 }
574 }
575
576 public String toString() {
577 if (perms == null)
578 init();
579 return perms.toString();
580 }
581}
Launcher.java这个类私有了构造方法,在成员变量中进行了实例化。同时定义了一个ClasLoader loader的变量,用于保存系统类加载器。
1private static Launcher launcher = new Launcher();
2...
3private ClassLoader loader;
在构造方法中主要有3个动作:
- 实例化扩展类加载器
1 // Create the extension class loader
2 ClassLoader extcl;
3 try {
4 extcl = ExtClassLoader.getExtClassLoader();
5 } catch (IOException e) {
6 throw new InternalError(
7 "Could not create extension class loader", e);
8 }
- 实例化系统类加载器
1 try {
2 loader = AppClassLoader.getAppClassLoader(extcl);
3 } catch (IOException e) {
4 throw new InternalError(
5 "Could not create application class loader", e);
6 }
7
- 将系统类加载器设置到线程上下文类加载器
1// Also set the context class loader for the primordial thread.
2 Thread.currentThread().setContextClassLoader(loader);
ExtClassLoader和AppClassLoader是URLClassLoader的子类,类的主要加载逻辑已由URLClassLoader和器父类加载器完成了,这2个子类主要定义了类的加载路径。
对于ExtClassLoader,处理加载路径逻辑:
1 private static File[] getExtDirs() {
2 String var0 = System.getProperty("java.ext.dirs");
3 File[] var1;
4 if (var0 != null) {
5 StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
6 int var3 = var2.countTokens();
7 var1 = new File[var3];
8
9 for(int var4 = 0; var4 < var3; ++var4) {
10 var1[var4] = new File(var2.nextToken());
11 }
12 } else {
13 var1 = new File[0];
14 }
15
16 return var1;
17 }
从系统参数"java.ext.dirs"值获取加载的路径值,️以分隔符为标记拆分为File数组,包含了扩展类加载器加载的全部路径。
对于AppClassLoader,处理逻辑:
1 final String s = System.getProperty("java.class.path");
2 final File[] path = (s == null) ? new File[0] : getClassPath(s);
类似地,从classpath中解析出所有的加载路径。
从AppClassLoader的构造方法看出,它以扩展类加载器为父类加载器。
1 /*
2 * Creates a new AppClassLoader
3 */
4 AppClassLoader(URL[] urls, ClassLoader parent) {
5 super(urls, parent, factory);
6 ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
7 ucp.initLookupCache(this);
8 }