Ставь лайк и потом смотри, вырабатывай полезную привычку
Когда речь заходит о ClassLoader, первое, что приходит на ум, должно быть "родительское делегирование". При загрузке классов в первую очередь используется родительский загрузчик классов. Однако помимо этой модели делегирования есть много деталей, которые стоит изучить.
время загрузки
В дополнение к явному вызову ClassLoader.loadClass для загрузки класса, JVM также будет выполнять операцию загрузки класса в следующих пяти сценариях (ClassLoader.loadClassInternal вызывается JVM).
- При создании экземпляра объекта с ключевым словом new, при чтении или установке статического поля класса (за исключением статических полей, измененных с помощью final, и результат был помещен в пул констант во время компиляции), а также при вызове статического метода класса класс когда.
- При использовании метода пакета java.lang.reflect для выполнения вызова отражения к классу, если класс не был инициализирован, сначала необходимо запустить его инициализацию.
- При инициализации класса, если обнаруживается, что его родительский класс не был инициализирован, ему необходимо сначала инициировать инициализацию своего родительского класса.
- Когда виртуальная машина запускается, пользователю необходимо указать основной класс для выполнения (класс, содержащий метод main()), и виртуальная машина сначала инициализирует этот основной класс.
- При использовании поддержки динамического языка JDK 1.7, если последним результатом синтаксического анализа экземпляра java.lang.invoke.MethodHandle является дескриптор метода REF_getStatic, REF_putStatic и REF_invokeStatic, а класс, соответствующий этому дескриптору метода, не был инициализирован, его нужно сначала запустить, его инициализацию.
Вышеупомянутые тайминги загрузки в совокупности называются активными эталонными методами; кроме того, другие методы ссылки на классы не будут запускать загрузку класса.
Например, в следующем случае это не активная ссылка, и класс не будет загружен.
public class NotInitialization {
public static void main(String[] args) {
//根据场景1,读取的是常量,不会造成类的初始化
System.out.println(ConstClass.HELLOWORLD);
}
}
class ConstClass{
static final String HELLOWORLD = "hello world";
static {
System.out.println("ConstClass init!");
}
}
Class.forName
Загрузка класса может осуществляться в виде Class.forName, но здесь используется загрузчик класса вызывающего, то есть загрузчик класса того класса, который инициирует вызов метода Class.forName
public static Class<?> forName(String className)
throws ClassNotFoundException {
//获取caller Class
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
«Транзитивность» загрузчиков классов
Во-первых, давайте поговорим о двух понятиях.определение загрузчикаа такжеНачальный загрузчик
Существует существующий ClassLoader A, если класс X напрямую определяется A (вместо делегирования родительского classLoader для загрузки в A), то ClassLoader A называется классом X.определить загрузчик, также называемый ClassLoader A, определяет класс X
Когда ClassLoader поручает родительскому classLoader загрузить класс (loadClass), то classLoader для loadClass и родительский classLoader для defineClass не совпадают.
Существует ClassLoader B, который загружает класс Y с помощью метода loadClass ClassLoader B. Независимо от того, определяет ли ClassLoader B непосредственно класс Y или делегирует родительский classLoader для определения класса Y, тогда ClassLoader B относится к классу Y.загрузчик начального класса.
Просто если класс Y загружается непосредственно ClassLoader B, то класс Yопределить загрузчика такженачальный загрузчикОба являются ClassLoader B; если он загружается родительским классом classLoader C, тоопределить загрузчикэто ClassLoader C, иначальный загрузчикэто ClassLoader B
Как показано на рисунке ниже, для загруженного класса X используется ClassLoader A.начальный загрузчик, и фактически ClassLoader A делегирует ClassLoader B для завершения определения, поэтому ClassLoader Bопределить загрузчик
Класс, загруженный в виде Class.forName, фактически использует вызывающую программу.определить загрузчик
Хоть этот абзац и похож на скороговорку... но он же и ключ к ClassLoader, а характеристики передачи ClassLoader очень важны
для вышеупомянутого"активное цитирование"В механизме заряжания есть некоторые детали, на которые необходимо обратить внимание:
- Когда JVM интерпретирует класс, на самом деле"ленивая загрузка", указанный класс будет проанализирован после того, как строка интерпретации и выполнения встретит ссылку; например, если класс вызывается в теле метода, он будет загружен только при выполнении этой строки.
- Для того же экземпляра ClassLoader будет использоваться класс, который не был загружен в текущем классе.Инициировать загрузчик определений ссылочного класса (вместо системного ClassLoader)загрузить
- Если ClassLoader уже загрузил определенный класс, он не будет загружен снова (даже loadClass не будет вызываться); например, класс A ссылается на класс X и класс B, а класс B также ссылается на класс X, затем выполнить, когда класс B , операция loadClass(X) больше не будет выполняться
В соответствии с приведенными выше характеристиками относительно просто настроить ClassLoader, например реализацию ClassLoader Executable Jar (Исполняемый Jar), предоставляемую Spring Boot:
Просто создайте ClassLoader (org.springframework.boot.loader.JarLauncher), отвечающий за загрузку пакета jar в пакете jar, а затем загрузите Main-Class в нашем коде через ClassLoader в классе ввода, чтобы загрузка могла быть done Пакет jar в пакете jar:
public void run() throws Exception {
//通过前面设置的“负载加载jar包内jar包的ClassLoader”,去加载我们程序中的main类
Class<?> mainClass = Thread.currentThread().getContextClassLoader()
.loadClass(this.mainClassName);
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { this.args });
}
Ссылаться на
- blogs.Oracle.com/Сэр раджа…
- docs.Oracle.com/JavaColor/spec…
- «Понимание виртуальной машины Java: расширенные функции и передовой опыт JVM (второе издание)», Чжимин Чжоу
Нелегко быть оригинальным, и несанкционированная перепечатка запрещена. Если моя статья полезна для вас, пожалуйста, поставьте лайк/добавьте в избранное/подпишитесь, чтобы поддержать и поддержать ее ❤❤❤❤❤❤