В Java есть два типа загрузки классов, один из которых определяется пользователем, а другой-загрузчик начальной загрузки, встроенный в JVM.
Существует три типа погрузчиков класса, встроенные в JVM, а именно класс Bootstrap ClassLoader, Extension ClassLoader (то есть ExtclassLoader) и System ClassLoader (то есть AppClassLoader).
Я не буду говорить о родительской делегации, когда JVM загружен, на Javaeye есть много статей, которые введены ...
Вы можете взглянуть на их конструкторы отдельно, где загрузчик начальной загрузки написан в c.
java.lang.classloader
Защищенный ClassLoader (ClassLoader) {SecurityManage Security = System.GetSecurityManager (); true; инициализировано = true;
Этот конструктор имеет два параметра и нет конструктора. Конструктор с параметрами проходит в родительском загрузке этого класса, в то время как конструктор без параметров будет обрабатывать загрузку класса, возвращаемый GetSystemClassloader () своим собственным родительским погрузчиком
Public Static ClassLoader GetSystemClassLoader () {// Возвращенный загрузчик класса присваивается initsystemClassloader (); CCL = GetCallerClass (); if (! sclset) {if (scl! = null). OOPS = null; // Значение назначено scl = l.getclassloader (); .... .....................................}} sclset = true; Загрузчик родительского класса здесь - SCL, который получает L.GetClassLoader (), getClassLoader (), а затем посмотрите на исходный код пускового средства:
Private Static Launcher Launcher = New Launcher ();
Public Static Launcher getLauncher () {return Launcher; ); Appclassloader, то есть GetSystemClassLoader возвращает AppClassLoader = AppClassLoader.getAppClassLoader (EXTCL); Поток, чтобы предотвратить путаницу, вызванную классовой загрузкой в многопользовательстве (я понимаю это, ха -ха) // также установите загрузку класса контекста для первичного потока. .................................................. ................................................ .. ..............} / * * Возвращает загрузку класса, используемый для запуска основного приложения. Из этого мы видим, что родительский загрузчик Appclassloader является extclassloader, и что такое родительский загрузчик extclassloader? Давайте посмотрим на конструктор extclassloader:
public extclassloader (файл [] dirs) бросает ioexception {super (getexturls (dirs), null, factory);Его родительский погрузчик пуст, в то время как его родительский класс верхнего уровня-Java.lang.classloader.
Защищенный синхронизированный класс <?> LoadClass (String name, Boolean Resolve) Throws ClassNotFoundException {// Сначала проверяйте, был ли класс уже загружен класс C = FindLoadClass (name); ! = NULL) {// Сначала вызовите родительский загрузчик. {// Если все еще не найденЗдесь FindBootStrapClass0 должен вызвать загрузку Bootstrap ClassLoader, наибольший загрузчик класса Core для загрузки класса.
Наконец, мы видим, что загрузчик класса, возвращаемый GetSystemClassLoader (), является AppClassLoader.
Анализ механизма класса класса Java
JDK Default ClassLoader
JDK предоставляет следующие загрузчики класса по умолчанию
Bootstrp Loader
BootStrp Loader написан на языке C ++. JRE/классы.
Extclassloader
Загрузчик загрузки загружает extclassloader и устанавливает родительский загрузчик ExtClassLoader на загрузку BootStrp. Это все классы каталогов в библиотеках пути и классов в пути, указанной системной переменной java.ext.dirs.
Appclassloader
После загрузки загрузчика BootStrp загружает extclassloader, загрузчик Appclassloader будет загружен, а родительский загрузчик Appclassloader указан как ExtClassLoader. Appclassload также написан в Java. Это JAR Document, который также является загрузчиком класса по умолчанию для Java -программ.
Подводя итог, взаимосвязь между ними может быть описана на следующем рисунке:
Родительская модель делегации
Загрузка класса в Java применяет механизм делегата родителей.
В настоящее время ClassLoader впервые проверяет, был ли этот класс загружен из класса, который он уже загрузил.
Каждый загрузчик класса имеет свой собственный кэш загрузки.
Когда кэш -загрузчик не найден, родительский загрузчик класса делегирован для его загрузки. путь к загрузке Bootprp.
Когда все родительские загрузки класса не загружаются, они загружаются текущим загрузчиком класса и помещают их в свой собственный кэш, чтобы их можно было вернуть непосредственно в следующий раз, когда будет запрос на загрузку.
Говоря об этом, вы можете задаться вопросом, почему Java принимает такой механизм делегирования? Чтобы понять эту проблему, мы представляем еще одну концепцию «пространство имен» о ClassLoader, что означает, что для определения определенного класса вам нужно полностью квалифицированное имя класса и загрузить этот класс класса, чтобы совместно определить его. То есть, даже если полностью квалифицированные имена двух классов одинаковы, потому что разные загрузчики класса загружают этот класс, то это другой класс в JVM. Понимая пространство имен, давайте посмотрим на модель делегатов. После принятия модели делегатов интерактивные возможности различных загрузчиков увеличиваются. Важна ваша программа, в ней так много загрузчиков классов, поэтому эти классы могут быть обмены, что позволяет избежать путаницы, вызванной различными погрузчиками класса после загрузки разных классов с одинаковым именем.
Как настроить ClassLoader
В дополнение к классу по умолчанию, упомянутому выше, Java также позволяет приложениям настраивать ClassLoader. Нам нужно обратить внимание на несколько важных методов:
1. Метод загрузки
Метод Loadclass объявляет
открытый класс <?> LoadClass (String name) Throws ClassNotFoundException
Выше -прототип декларации метода нагрузки. Давайте посмотрим на код этого метода, чтобы увидеть, как он реализует родительскую делегирование.
Метод LoadClass реализовать
public class <?> LoadClass (String name) Throws classNotFoundException {return LoadClass (name, false);}Из вышеперечисленного мы видим, что метод LoadClass вызывает метод LoadCclass (имя, false), поэтому давайте посмотрим на реализацию другого метода LoadClass.
Class LoadClass (название строки, логическое решение)
Защищенный синхронизированный класс <?> LoadClass (имя строки, логическое разрешение) выбрасывает ClassNotFoundException {// сначала, проверьте, был ли класс уже загружен класс c = findloadedClass (name); // Проверьте, был ли класс загружен, если (c = = null) {try {if (parent! = null) {c = parent.loadclass (имя, false); } else {c = findbootStrapClass0 (name); // Если нет родительского загрузчика класса, делегируйте загрузку Bootstrap для загрузки}} Catch (classNotFoundException e) {// Если все еще не найдено, тогда вызывает e findclass в порядке // Найдите класс. }} if (resolve) {resolVeclass (c);В приведенном выше коде я добавил комментарии, чтобы четко увидеть, как работает механизм родительского делегирования класса Load. Одна вещь, которую мы должны отметить здесь, это то, что открытый класс <?> LoadClass (String name) Chos ClassNotFoundException не помечается как окончательный, что означает, что мы можем переопределить этот метод, что означает, что родительский механизм делегирования может быть нарушен. Кроме того, мы заметили, что есть метод Findclass выше.
2.findclass
Мы проверяем исходный код java.lang.classloader и обнаруживаем, что реализация Findclass выглядит следующим образом:
Защищенный класс <?> FindClass (String name) Throws ClassNotFoundException {Throw New ClassNotFoundException (name);}Мы видим, что реализация этого метода по умолчанию состоит в том, чтобы напрямую бросить исключения, но на самом деле этот метод оставляется наше приложение для переопределения. Конкретная реализация зависит от вашей логики реализации. Давайте опишем DefineClass позже. Хорошо, через приведенный выше анализ мы можем сделать следующие выводы:
Когда мы пишем нашего собственного загрузчика класса, если мы хотим следовать механизму родительского делегирования, нам нужно только переопределить Findclass.
3. decianclass
Давайте сначала посмотрим на исходный код deciplass:
DefineClass
Защищенный окончательный класс <?> decipleclass (имя строки, byte [] b, int off, int len) бросает classformaterror {return decileclass (name, b, off, len, null);}Из приведенного выше кода мы видим, что этот метод определяется как окончательный, что означает, что этот метод не может быть переоборудован. Файл должен соответствовать определению классов, указанных спецификацией виртуальной машины Java. Этот метод, наконец, будет вызвать нативный метод для реализации загрузки реального класса.
Хорошо, через описание выше, давайте подумаем о следующем вопросе:
Если мы сами написали класс java.lang.string, можем ли мы заменить класс, который называет сам JDK?
Ответ нет. Мы не можем этого достичь. Почему? Я вижу много онлайн -объяснений о том, что родительский механизм делегирования решает эту проблему, но на самом деле это не очень точно. Поскольку родительский механизм делегирования может быть сломан, вы можете написать класс -загрузчик для загрузки класса java.lang.string, который вы написали, но вы обнаружите, что он не будет успешно загружаться, особенно потому, что он предназначен для класса, начиная с Java.*, JVM Реализация гарантировала, что она должна быть загружена BootStrp.
Сценарии, которые не следуют «механизму делегирования родителей»
Вышеупомянутое, что родительский механизм делегирования состоит в том, чтобы в основном реализовать проблему взаимодействия классов, загруженных между различными загрузчиками класса. Родительский класс погрузчик в Java. Давайте поговорим о возникновении этой ситуации.
В Java существует стандарт SPI (интерфейс поставщика услуг), в котором используются библиотеки SPI, такие как JDBC, JNDI и т. Д. Мы все знаем, что JDBC нуждаются в драйверах, предоставленных третьими лицами, а пакет JAR драйвера помещается в самое приложение. ClassPath и API JDBC являются частью положения JDK, и он был загружен BootStrp. Java представляет концепцию Context Class Class Loader. Драйвер, это нормально загружать загрузчик контекста потока.
Кроме того, для реализации более гибкого загрузчика класса OSGI и некоторых серверов приложений Java он также нарушает родительский механизм делегирования.