Это не отвечает на первоначальный вопрос, но поскольку вопрос высоко ранжируется и связывается для любого ContextClassLoader
запроса, я думаю, что важно ответить на связанный вопрос о том, когда следует использовать загрузчик класса контекста. Краткий ответ: никогда не используйте загрузчик классов контекста ! Но установите его, getClass().getClassLoader()
когда вам нужно вызвать метод, который отсутствуетClassLoader
параметр.
Когда код из одного класса просит загрузить другой класс, правильный загрузчик класса, который нужно использовать, является тем же загрузчиком класса, что и класс вызывающей стороны (т. Е. getClass().getClassLoader()
). Именно так все и работает в 99,9% случаев, потому что именно это делает сама JVM. при первом создании экземпляра нового класса, вызове статического метода или обращении к статическому полю.
Когда вы хотите создать класс с использованием отражения (например, при десериализации или загрузке настраиваемого именованного класса), библиотека, которая выполняет отражение, должна всегда спрашивать приложение, какой загрузчик классов использовать, получая в ClassLoader
качестве параметра из приложения. Приложение (которое знает все классы, которые нужно построить) должно передать егоgetClass().getClassLoader()
.
Любой другой способ получить загрузчик классов неверен. Если библиотека использует такие хаки, как Thread.getContextClassLoader()
, sun.misc.VM.latestUserDefinedLoader()
или sun.reflect.Reflection.getCallerClass()
это ошибка, вызванная недостатком API. По сути, Thread.getContextClassLoader()
существует только потому, что тот, кто разработал ObjectInputStream
API, забыл принятьClassLoader
в качестве параметра, и эта ошибка преследует сообщество Java и по сей день.
Тем не менее, многие классы JDK используют один из нескольких хаков, чтобы угадать какой-либо загрузчик классов. Некоторые используют ContextClassLoader
(что дает сбой, когда вы запускаете разные приложения в общем пуле потоков, или когда вы покидаете ContextClassLoader null
), некоторые обходят стек (что не удается, когда прямой вызывающий класс сам является библиотекой), другие используют загрузчик системного класса (что нормально, если задокументировано использование только классов в CLASSPATH
) или загрузчике классов, а некоторые используют непредсказуемую комбинацию вышеперечисленных методов (что только делает вещи более запутанными). Это привело к сильному рыданию и скрежету зубов.
При использовании такого API, сначала попробуйте найти перегрузку метода, который принимает загрузчик классов в качестве параметра . Если разумного метода нет, попробуйте установить ContextClassLoader
вызов API before (и затем сбросить его):
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
ClassB
должен быть на classpathClassA
загрузчика (илиClassA
родителей загрузчика)? Не может лиClassA
загрузчик переопределитьloadClass()
, чтобы он мог успешно загружаться,ClassB
даже еслиClassB
он не находится в своем пути к классам?