如何选择Classloader? [英] How is the Classloader for a class chosen?

查看:89
本文介绍了如何选择Classloader?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

动机



假设我们有一个类加载层次结构,如下所示:

  Bootstrap 
|
系统
|
自定义

假设自定义 Classloader用于加载类 com.example.SomeClass 。它检查 System 类加载器是否可以加载它,再次检查 Bootstrap 类加载器是否可以加载它。由于两者都不能, com.example.SomeClass 自定义类加载器加载。



任何 com.example.SomeClass 的类都依赖于它。我相信我理解这个过程。



问题



我不明白为什么自定义会首先尝试加载 com.example.SomeClass 。如何在Java应用程序中选择当前的类加载器?

解决方案

小介绍



正如您所知,默认情况下,Java使用引导类加载器和系统类加载器。第一个负责加载引导类(它的类路径包含诸如rt.jar之类的工件),第二个负责保存应用程序的类路径。通常,在环境变量中定义或在JVM中给出的类路径开始使用 -cp 参数。



答案



com.example.SomeClass 将由您的自定义类加载器加载自定义仅当发生以下两种情况之一时:要么在启动时定义自定义类加载器以用作系统类加载器,要么在运行时通过它显式加载类。



关于每个选项的更多信息:




  • 应用程序启动时:您可以定义何时启动JVM实例,而不是使用Java的默认系统类加载器,而是使用您自己的。为此,只需使用定义的以下环境变量调用java:

      -Djava.system.class.loader = my.tests .classloaders.Custom 

    在这种情况下,会发生的是所有类您在该JVM实例中的应用程序实际上将由自定义类加载器加载。


  • 期间运行时:您可以在运行时使用自定义类加载器加载类。这是通过创建自定义类加载器的实例并从中加载类来实现的。

      ClassLoader classloader = new CustomClassLoader(); 
    类someClass = classloader.loadClass(com.example.SomeClass);




就像@Noofiz在他的回答中说过一次你有一个类加载所有需要但尚未加载的引用类通过关联的类加载器加载。因此,如果使用自定义类加载器加载一个类,则所有引用的类也将通过它加载。加载所有类时,您可以执行任何操作,记录正在加载的类,委托父类加载器,自己加载类...



一些额外的信息



通常,实现自定义类加载器的最佳方法是使用您提到的委托模型。这是因为类实际上不仅由类的字节码定义,而且还由类加载器定义,这意味着由两个不同类加载器加载的类将不是同一类



这意味着当您的自定义类加载器委托给其父级时,您确保该类可用于更宽的范围。大多数情况下,这将是你想要的,但并非总是如此。



如果由于某种原因你想要类隔离,那么你的自定义类加载器可能会以相反的方式实现。首先,它尝试自己加载类,并且只有在找不到类(或者是JVM系统类或您可能想要跳过的任何其他类)时才将其委托给它的父级。例如,Web应用程序容器以这种方式工作,允许上下文重新部署(基本上它们丢弃类加载器并创建一个新的加载所有内容)和Web应用程序之间的完全类隔离。



<正如我已经说过的那样,处理类加载并不是微不足道的,要么你真的知道你在做什么,要么你肯定会发现自己陷入了一些奇怪的伏都教问题。



可能已经过于偏离主题了,但是如果你想获得更多关于类加载器和隔离的动手,你可以检查一个旧的开放源项目名为 classworlds 。即使这个项目很老,我也建议它,因为它是一个小项目,充满了关于类加载机制的知识,你可以很容易地深入研究。


Motivation

Assume that we have a class loading hierarchy that looks like this:

 Bootstrap
     |
  System
     |
  Custom

Let's say that Custom Classloader is used for loading a class com.example.SomeClass. It checks if the System classloader can load it which again checks whether Bootstrap classloader can load it. Since both can't, com.example.SomeClass is loaded by Custom classloader.

Any class that com.example.SomeClass depends on goes throught the same. I believe I understand that process.

Question

I don't understand why Custom would try to load com.example.SomeClass in the first place. How is the current classloader chosen in an Java application?

解决方案

Small intro

As you already know, by default Java uses the bootstrap classloader and the system classloader. The first is responsible for loading bootstrap classes (its classpath contains artifacts such as rt.jar) and the second is responsible for holding your application's classpath. Usually the classpath either defined in your environment variable or given at JVM start using the -cp argument.

The answer

The class com.example.SomeClass will be loaded by your custom classloader Custom only if one of two things happen: either you define your custom classloader at startup to be used as system classloader or during running time you explicitly load the class through it.

A bit more about each option:

  • At application start-up: you can define when starting a JVM instance that instead of using Java's default system class loader you want to use your own. To do so, simply call java with the following environment variable defined:

    -Djava.system.class.loader=my.tests.classloaders.Custom
    

    In this case what happens is that all classes from your application in that JVM instance will actually be loaded by Custom class loader.

  • During runtime: you can at runtime load a class with your custom class loader. This is achieved creating an instance of your custom class loader and loading your class from it

         ClassLoader classloader = new CustomClassLoader();
         Class someClass = classloader.loadClass("com.example.SomeClass");
    

Like @Noofiz said in his answer once you have one class loaded all referenced classes that are required and not yet loaded are loaded through the associated class loader. So, if you load one class with your custom class loader all referenced classes will also be loaded through it. When loading all classes you can do whatever you want, log which classes are being loaded, delegate to parent class loader, load the classes by yourself...

Some extra info

Usually the best way to implement a custom class loader is to use the delegation model as you mentioned. This is because a class is actually defined not only by the classes' bytecode but also by its class loader, which means that a class loaded by two different class loaders won't be the same class.

This means that when your custom class loader is delegating to its parent you're making sure that class is available to a wider scope. Most of the time this will be what you want, but not always.

If for some reason you want class isolation then your custom class loader might be implemented the other way around. First it tries to load the class by itself and only if it doesn't find the class (or is a JVM system class or any other classes you might want to skip) delegates it to its parent. For example, web application containers work this way, allowing context redeploy (basically they discard the class loader and create a new one loading everything again) and full class isolation between web apps.

As I already said, handling class loading is not trivial at all and either you really know what you are doing or you'll certainly find yourself in some weird voodoo troubles.

Maybe already way too off topic, but if you wanna get a bit more hands on regarding class loaders and isolation you can check an old open source project called classworlds. Even though this project is old I'm suggesting it because it's a small project, filled with knowledge about class loading mechanisms which you can easily dive into.

这篇关于如何选择Classloader?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆