深入理解JVM-类加载及类加载器 (12)

image-20200211063824377

Launcher(); //双亲处理的机制。精髓 public Launcher() { // Create the extension class loader 创建扩展类加载器 ClassLoader extcl; try { extcl = ExtClassLoader.getExtClassLoader(); } catch (IOException e) { throw new InternalError( "Could not create extension class loader", e); } // Now create the class loader to use to launch the application 创建应用类加载器 try { loader = AppClassLoader.getAppClassLoader(extcl); } catch (IOException e) { throw new InternalError( "Could not create application class loader", e); } // Also set the context class loader for the primordial thread. // 为当前的执行线程设置上下文类加载器。(重要。重要。重要。) // 如果没有通过setContextCLassLoader(ClassLoader cl)进行设置的话,线程将继承其父线程的上下文类加载器。Java应用运行时的初始线程的上下文类加载器是系统类加载器 Thread.currentThread().setContextClassLoader(loader); // Finally, install a security manager if requested String s = System.getProperty("java.security.manager"); if (s != null) { // init FileSystem machinery before SecurityManager installation sun.nio.fs.DefaultFileSystemProvider.create(); SecurityManager sm = null; if ("".equals(s) || "default".equals(s)) { sm = new java.lang.SecurityManager(); } else { try { sm = (SecurityManager)loader.loadClass(s).newInstance(); } catch (IllegalAccessException e) { } catch (InstantiationException e) { } catch (ClassNotFoundException e) { } catch (ClassCastException e) { } } if (sm != null) { System.setSecurityManager(sm); } else { throw new InternalError( "Could not create SecurityManager: " + s); } } } Class.forName();

第一次使用这个方法的时候,是在学习JDBC的时候获取数据库连接。那个时候只用到了一个参数的构造方法

java.lang.Class<T> public static Class<?> forName(@NonNls String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException Returns the Class object associated with the class or interface with the given string name, using the given class loader. Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface. The specified class loader is used to load the class or interface. If the parameter loader is null, the class is loaded through the bootstrap class loader. The class is initialized only if the initialize parameter is true and if it has not been initialized earlier. //使用给定的类加载器返回与具有给定字符串名称的类或接口关联的Class对象。 给定类或接口的完全限定名称(采用getName返回的相同格式),此方法尝试查找,加载和链接该类或接口。 指定的类加载器用于加载类或接口。 如果参数加载器为null,则通过引导类加载器加载该类。 仅当initialize参数为true且之前尚未初始化时,才对类进行初始化。 If name denotes a primitive type or void, an attempt will be made to locate a user-defined class in the unnamed package whose name is name. Therefore, this method cannot be used to obtain any of the Class objects representing primitive types or void. If name denotes an array class, the component type of the array class is loaded but not initialized. //如果name表示原始类型或void,则将尝试在名称为name的未命名包中定位用户定义的类。 因此,该方法不能用于获取表示原始类型或void的任何Class对象。如果name表示数组类,则将加载但不初始化该数组类的组件类型。 For example, in an instance method the expression: Class.forName("Foo") is equivalent to: Class.forName("Foo", true, this.getClass().getClassLoader()) Note that this method throws errors related to loading, linking or initializing as specified in Sections 12.2, 12.3 and 12.4 of The Java Language Specification. Note that this method does not check whether the requested class is accessible to its caller. If the loader is null, and a security manager is present, and the caller's class loader is not null, then this method calls the security manager's checkPermission method with a RuntimePermission("getClassLoader") permission to ensure it's ok to access the bootstrap class loader. /*例如,在实例方法中,表达式为: Class.forName(“ Foo”) 等效于: Class.forName(“ Foo”,yes,this.getClass().getClassLoader()) 请注意,此方法会引发与Java语言规范的12.2、12.3和12.4节中指定的加载,链接或初始化有关的错误。 请注意,此方法不检查其调用者是否可以访问所请求的类。 如果加载程序为null,并且存在安全管理器,并且调用方的类加载器不为null,则此方法使用RuntimePermission(“ getClassLoader”)权限调用安全管理器的checkPermission方法,以确保可以访问引导程序类加载器 。*/ Params: name – fully qualified name of the desired class initialize – if true the class will be initialized. See Section 12.4 of The Java Language Specification. loader – class loader from which the class must be loaded /*参数: 名称-所需类别的完全限定名称 初始化–如果为true,则将初始化该类。 参见Java语言规范的12.4节。 loader –必须从中加载类的类加载器*/ @CallerSensitive public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException { Class<?> caller = null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Reflective call to get caller class is only needed if a security manager // is present. Avoid the overhead of making this call otherwise. caller = Reflection.getCallerClass(); if (sun.misc.VM.isSystemDomainLoader(loader)) { ClassLoader ccl = ClassLoader.getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } } return forName0(name, initialize, loader, caller); } @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); } 线程上下文类加载器

当前类加载器(Current ClassLadert):加载当前类的加载器。

每一个类都会尝试使用自身的类加载器(即加载自身的类加载器)来加载其他的类(指的是所依赖的类)。

如: 如果CLassx引用了ClassY,那么ClassX的类加载器就会去加载CLassY(前提是ClassY尚未被加载)

线程上下文类加载器(Context CLassloader)

线程上下文类加载器是从jdk1.2开始引入的,类Thread中的getContextClassLoader();与setContextClassLoadert();分别用来获取和设置上下文类加载器。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpszsp.html