圆圆网络 手游攻略 新游动态 类加载器的加载顺序,自定义类加载器的应用场景

类加载器的加载顺序,自定义类加载器的应用场景

时间:2024-05-01 23:35:14 来源:头条 浏览:0

系统自身的类加载器是如何加载的?(重要)JVM内置的启动类加载器加载java.lang.classLoader以及其他平台的Java平台类。当JVM 启动时,会执行特殊的机器代码。他加载扩展类加载器和系统类加载器。这段特殊的机器代码称为引导类加载器(bootstrap)。引导类加载器不是Java 类(用C++ 编写);所有其他加载器都是Java。 Class,start 类加载器是特定于平台的机器指令,负责启动整个加载过程。所有类加载器(启动类加载器除外)都是作为Java 类实现的。然而,必须始终有一个组件来加载初始Java类加载器,以便整个加载过程顺利进行。加载初始的纯Java类加载器是启动类的责任。启动类加载器还负责加载JRE正常运行所需的基本组件,例如java.util和java.lang包中的类。 thread 上下文类加载器的典型使用模式(get-use) -restore) thread 上下文类加载器的典型使用模式(get-use-restore) //获取类加载器classLoader=Thread.currentThread.getContextClassLoader() ; try{ //设置要使用的类加载器//如果启动了cls类加载器,就可以加载到你的实现类中//springboot加载MATE-INF/下的spring.factories,即线程类加载器Thread.currentThread.setContextClassLoader( cls); //使用MyMethod(); }finally{ //如果没有恢复,则使用类加载器。 //Restore Thread.currentThread.setContextClassLoader(classLoader); } MyMethod 调用Thread.currentThread().getContextClassLoader() 来获取当前线程的上下文类加载器。确定的事情。如果一个类是由类加载器A加载的,那么该类的依赖类也会由同一个类加载器加载(除非该依赖类之前已经加载过) 例如:启动类加载器无法扫描系统类加载器。内容上下文类加载器就是这个问题的解决方案。 ContextClassLoader的功能是重写Java的类加载委托机制(如上所述)。当上层提供统一的接口供下层实现时,下层也必须在上层中加载(或实例化)。加载类时,必须使用线程上下文类加载器,以便更高级别的ClassLoader 可以找到并加载该类。

类加载器的加载顺序,自定义类加载器的应用场景

可以直接使用getClassLoader来获取系统类加载器并加载相应的类,但是为什么要使用上下文类加载器呢?

方便的是,所有执行的代码都在线程内部。可以随时检索相应的上下文类加载器,并用于解决底层类的高层加载问题。有某些情况。当前线程类加载器必然是系统类加载器。目前无法加载类路径下的.class 文件。定制系统类加载器/* 在运行时,Java 类由类的完全限定名称(二进制名称)和定义的类加载器组成。类加载器(define class loader) 用于加载类。装载机)。即使.class 文件具有完全相同的字节码并且从相同位置加载,由两个不同加载器加载的具有相同名称(即相同的完全限定名称)的类也是不同的。 *//* Oracle的热点实现中,如果系统属性sun.boot.class.path修改错误,操作会失败,错误信息如下: Error whileinitializing VM. Occurred java/lang/NOClassDefFoundError: java/lang/Object */public class MyTest23 { public static void main(String[] args) { System.out.println(System.getProperty('sun.boot.class.path') );//根类加载器System.out . println( System.getProperty('java.ext.dirs'));//扩展类加载器System.out.println(System.getProperty('java.class.path') );//应用程序类加载器应该是:编译好的.class文件放在classes下面,这样就被类加载器加载/* JVM内置的启动类加载器加载java.lang.classLoader和其他平台的Java平台类。执行特殊的机器代码来加载扩展和系统类加载器。这种特殊的机器代码称为引导类加载器(bootstrap)。引导类加载器不是Java类,而是其他加载器。启动类加载器是特定于平台的机器指令,负责启动整个加载过程。所有类加载器(启动类加载器除外)都是作为Java 类实现的。然而,必须始终有一个组件来加载初始Java类加载器,以便整个加载过程顺利进行。加载初始的纯Java类加载器是启动类的责任。启动类加载器还负责加载JRE正常运行所需的基本组件,例如java.util和java.lang包中的类。 */System.out.println(ClassLoader.class.getClassLoader( )); //null JVM内置的启动类加载器加载java.lang.classLoader以及其他平台的Java平台类。 //扩展类加载器和系统类加载器也是由启动类加载器加载的。 System.out .println(Launcher.class.getClassLoader());//null APPClassLoader和ExtClassLoader都是类的静态内部类,所以当第二个类加载器加载时,加载的类的其他内容由类加载器加载系统。 out.println(System.getProperty('java.system.class.loader'));//文件规范路径System.out.println(MyTest23.class.getClassLoader()); System.out.println(Test16.class . getClassLoader()); System.out.println(ClassLoader.getSystemClassLoader());//etSystemClassLoader 静态方法的类名。在ClassLoader 文档中获取系统类加载器。 }}

* 如果第一次调用此方法时定义了系统属性“java.system.class.loader”,则假定该属性的值是作为系统类加载器返回的类的名称。该类使用默认系统类加载器加载,并且必须定义一个公共构造函数,该构造函数采用ClassLoader 类型的单个参数作为委托的父级。然后创建一个实例* 使用此构造函数和默认的系统类加载器最终的类加载器被定义为系统类加载器* 第一次调用此方法时,系统属性'java.AppClassLoader 被用作系统类加载器已定义(对于java.system.class 和.loader 中指定的路径为null)。如果定义了系统属性,系统会导致默认的AppClassLoader 类加载器加载成为系统类加载器的自定义类加载器。值该属性的名称(方法名称)用作系统类加载器的名称。使用默认系统类加载器加载的类必须仅接受一种类加载器参数类型,并定义用作委托的公共构造函数。创建一个父类(ClassLoader成员变量对所有子类都可用)并使用默认的系统类加载器作为其构造函数参数。然后定制的类加载器就成为系统类加载器。如果直接运行的话

nullnullnull 目前,java.system.class.loader是加载系统类sun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$AppClassLoader@的自定义路径下的类,未指定。根据18b4aac2文档,当您更改默认的系统类加载器时,您需要在自定义类加载器中编写构造函数。构造函数只接受一个参数类型类加载器,该类加载器用作委托的父类。在Test16中添加相应的构造函数并重新编译。

//添加新的构造函数public Test16(ClassLoaderparent) { super(parent); } 在控制台输入将java.system.class.loader 指定的类加载器设置为com.example.demo.com.jvm 设置为.Test16并加载com.example.demo.com.jvm.MyTest23

java -Djava.system.class.loader=com.example.demo.com.jvm.Test16 com.example.demo.com.jvm.MyTest23nullnullcom.example.demo.com.jvm.Test16sun.misc.Launcher$AppClassLoader@18b4aac2sun .misc.Launcher$AppClassLoader@18b4aac2 //AppClassLoader当前是自定义系统类加载器的父类。父类可以直接加载输出com.example.demo.com.jvm.Test16@7852e922 //在源码分析问题1.为什么内置类加载器会加载指定位置?问题1、为什么系统类加载器是扩展类加载器的子类?DocumentationDocumentation

返回用于委托的系统类加载器。这是新ClassLoader 实例的默认委托父级,并且通常是用于启动应用程序的类加载器。 * * 该方法首先在运行时启动序列的早期被调用。重点是创建一个系统类加载器并将其设置为调用线程的* 上下文类加载器。 * * 默认系统类加载器是此类的依赖于实现的* 实例。 * * 系统属性“java.system.class.loader”被定义* 当第一次调用此方法时,该属性的值被假定为* 作为系统类加载器返回的类的名称* 类。将使用默认的系统类加载器* 进行加载,并且必须定义一个采用ClassLoader 类型的单个参数的公共构造函数,该构造函数将* 用作委托的父级。 * 然后使用此构造函数和默认系统类加载器作为参数创建一个实例。定义生成的类加载器* 成为系统类加载器* 返回用于委托的系统类加载器。这是新的(自定义)类加载器的默认委托父级,并且通常是用于启动应用程序的类加载器。 (Main方法) 该方法在程序执行过程中首先被调用。至此,系统类加载器就创建并设置好了,并设置为调用该方法的线程的上下文类加载器。默认系统类加载器实现取决于此类的实例。如果第一次调用该方法时定义了系统属性“java.system.class.loader”(如果java.system.class.loader中指定的路径为null且未定义,则AppClassLoader将用作系统类) .)装载机。如果定义了系统属性,系统会导致默认的AppClassLoader 类加载器加载成为系统类加载器的自定义类加载器。该属性的值(方法名称)用作系统类的名称。装载机。该类使用默认的系统类加载器。加载器必须定义一个公共构造函数,该构造函数恰好接受一个用作委托父类的参数类型的类加载器(ClassLoader 的成员变量可用于每个子类)。使用默认的系统类加载器作为此构造函数的函数参数。然后定制的类加载器就成为系统类加载器。

//获取系统类加载器@CallerSensitive public static ClassLoader getSystemClassLoader() { //初始化系统类加载器initSystemClassLoader(); if (scl==null) { return null; } //获取安全管理器SecurityManager sm=System. getSecurityManager(); if (sm !=null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; }

//初始化系统类加载器private static Synchronized void initSystemClassLoader() { //如果系统类加载器没有设置if (!sclSet) { //如果系统类加载器没有设置且不为空,则抛出异常be throw if (scl !=null) throw new IllegalStateException('递归调用'); //获取Launcher.getLauncher实例(下面解析) sun.misc.Launcher l=sun.misc .Launcher.getLauncher(); if ( l !=null) { //成功创建Throwable oops=null; //将Launcher的系统类加载器传递给当前类的类加载器scl=l.getClassLoader (); try { //获取类加载器对象(可以是appClassLoader或自定义类加载器) scl=AccessController.doPrivileged( new SystemClassLoaderAction(scl)); //将系统类加载器作为父加载器传递} catch (PrivilegedActionException pae) { oops=pae.getCause(); if (oops initationTargetException) { oops=oops.getCause(); } } if (oops !=null) { if (oopsinstanceof Error) { throw (Error) oops; else { //包装异常throw new Error(oops) ); } } } //系统类加载器配置现已完成sclSet=true; } }

//父委托private Final ClassLoaderparent; //系统类加载器//@GuardedBy('ClassLoader.class') private static ClassLoader scl; //如果设置了系统类加载器,则sclSet 为true //@GuardedBy( ' ClassLoader .class' ) private static boolean sclSet;SystemClassLoaderAction 类分析

class SystemClassLoaderActionimplements PrivilegedExceptionAction { private ClassLoaderparent; SystemClassLoaderAction(ClassLoaderparent) { this.parent=parent; } public ClassLoader run() throws Exception { //java.system.class.loader 获取系统属性String cls=System.getProperty(' java.system .class.loader'); if (cls==null) { //如果系统属性没有设置,则返回appClassLoader returnparent; }//如果系统类加载器是自定义的//获取cls中类的构造函数//Class.forName其name参数为(ClassLoader.class)加载cls对应的二进制名称,并用父类初始化(true)。 Constructor ctor=Class.forName(cls, true,parent) .getDeclaredConstructor(new) Class [] { ClassLoader.class }); //将父类加载器、系统类加载器传递给自定义类加载器//所以自定义类一旦加载器配置好了,就会被appClassLoader加载//获取自定义类加载器ClassLoader class ClassLoader sys=(ClassLoader) ctor.newInstance( //自定义类加载器接受ClassLoader构造函数,并定义父类参数为什么需要创建方法new Object[] {parent }); Thread.currentThread() .setContextClassLoader(sys); //返回自定义类加载器return sys; }}LaunchergetLauncher 文档

进入Launcher的无参数构造函数上下文类加载器

public Launcher() { //创建扩展类加载器Launcher.ExtClassLoader var1; //定义扩展类加载器try { //创建扩展类加载器实例var1=Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10 ) { throw new InternalError('无法创建扩展类加载器', var10); } try { //创建应用程序类加载器的实例,并将扩展类加载器连接到Launcher的父类和成员变量,并将其用作//为什么不使用扩展类加载器作为成员变量呢,既然应用程序类加载器可以作为它的子类来获取, this.loader=Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError( 'Could not create application class lower', var9); }//设置系统类加载器为当前执行线程,并设置上下文类加载器(*重要*) Thread.currentThread().setContextClassLoader(this.loader); //下一个安全管理器内容String var2=System.getProperty('java.security.manager'); if (var2 !=null) { SecurityManager var3=null; if (!''.equals(var2) !'default'. equals(var2)) { try { var3=(SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) ) { ; } } else { var3=new SecurityManager(); } if (var3==null) { throw new InternalError('可以

not create SecurityManager: " + var2); } System.setSecurityManager(var3); } }getExtClassLoader() 获取已经加载的扩展类加载器 static class ExtClassLoader extends URLClassLoader { //创建的扩展类加载器限制java.ext.dirs地区class文件 public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { //获取指定文件数组 System.getProperty("java.ext.dirs"); final File[] var0 = getExtDirs(); try { return (Launcher.ExtClassLoader)AccessController.doPrivileged( //返回时判断是否有权限去执行该操作 new PrivilegedExceptionAction() { public Launcher.ExtClassLoader run() throws IOException { //获取路径长度 int var1 = var0.length; //遍历每一个路径获取对应路径内容 for(int var2 = 0; var2 < var1; ++var2) {MetaIndex.registerDirectory(var0[var2]); } //返回扩展类对象给调用端 return new Launcher.ExtClassLoader(var0); } }); } catch (PrivilegedActionException var2) { throw (IOException)var2.getException(); } } doc 从java.class.path下加载指定内容getAppClassLoader(final ClassLoader var0) 获取系统类加载器 为什么扩展类加载器是系统类加载器父类? 解答如下 static class AppClassLoader extends URLClassLoader { final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); 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); } }); } AppClassLoader(URL[] var1, ClassLoader var2) { //调用父类完成双亲委托 将扩展类加载器作为父类 super(var1, var2, Launcher.factory); this.ucp.initLookupCache(this); } static class AppClassLoader extends URLClassLoader { final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); 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); } }); } AppClassLoader(URL[] var1, ClassLoader var2) { //调用父类完成双亲委托 将扩展类加载器作为父类 super(var1, var2, Launcher.factory); this.ucp.initLookupCache(this); }分析Class.forNamepublic static Class< > forName(String name, boolean initialize,ClassLoader loader)返回给定名字(String name)的类或接口的Class对象。用给定的( ClassLoader loader)的类加载器去加载这个方法试图定位、加载和链接类或接口。指定的类加载器用于加载类或接口。如果参数loader为null,类通过bootstrap类加载器加载。这个类类只有在initialize参数是true,尚未被初始化的情况下才会被初始化如果{String name}表示原始类型或void,则尝试将被用来在其未命名的包中寻找一个用户定义的类 name是{String name}。因此,这个方法不能用于获取表示原生类型或void的任何 Class对象。如果{String name}表示一个数组类,则组件类型(jvm)为加载了数组类,但没有初始化。例如,在一个实例方法中的表达式: Class.forName (" Foo ")Class< > caller = Reflection.getCallerClass();获取调用者的类加载器 //该会将调用者的类加载器去加载className的类 public static Class< > forName(String className) throws ClassNotFoundException { //获取调用者的Class对象 单参默认使用调用者的类加载器 Class< > caller = Reflection.getCallerClass(); //返回Class 使用C++实现 return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }相当于:Class.forName(“foo”,true, this.getClass.getClassLoader()) 这个方法是使用 自定义的类加载器无指定加载器使用当前加载这个类的加载器去加载这个类,如果指定了类加载器就会使用指定的类加载器去加载注意此方法抛出与加载、链接或初始化相关的错误按照的第12.2、12.3和12.4节的规定进行初始化Java语言规范。注意,这个方法不会检查被请求的类是否存在调用者可以访问*。String name:指定类完整的限定名boolean initialize:是否初始化ClassLoader loader:用于去加载这个类的类加载器源代码 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. //获取调用forname方法的类的Class对象 caller = Reflection.getCallerClass(); if (sun.misc.VM.isSystemDomainLoader(loader)) { //获取调用forname方法的类的Class对象的类加载器 ClassLoader ccl = ClassLoader.getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { //安全检查 sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } } //c++代码 return forName0(name, initialize, loader, caller); }
标题:类加载器的加载顺序,自定义类加载器的应用场景
链接:https://yyuanw.com/news/xydt/13345.html
版权:文章转载自网络,如有侵权,请联系删除!
资讯推荐
更多
阴阳师4月22日更新内容:帝释天上线技能调整,红莲华冕活动来袭

阴阳师4月22日更新内容:帝释天上线技能调整,红莲华冕活动来袭[多图],阴阳师4月22日更新的内容有哪些?版本更新

2024-05-01
四川电视台经济频道如何培养孩子的学习习惯与方法直播在哪看?直播视频回放地址

四川电视台经济频道如何培养孩子的学习习惯与方法直播在哪看?直播视频回放地址[多图],2021四川电视台经济频

2024-05-01
湖北电视台生活频道如何培养孩子的学习兴趣直播回放在哪看?直播视频回放地址入口

湖北电视台生活频道如何培养孩子的学习兴趣直播回放在哪看?直播视频回放地址入口[多图],湖北电视台生活频道

2024-05-01
小森生活金币不够用怎么办?金币没了不够用解决方法

小森生活金币不够用怎么办?金币没了不够用解决方法[多图],小森生活金币突然就不够用的情况很多人都有,金币没

2024-05-01