Это не отвечает на исходный вопрос, но, поскольку вопрос имеет высокий рейтинг и связан с любым ContextClassLoader
запросом, я думаю, что важно ответить на связанный вопрос о том, когда следует использовать загрузчик класса контекста. Краткий ответ: никогда не используйте загрузчик классов контекста! Но установите его в getClass().getClassLoader()
, когда вам нужно вызвать метод, у которого отсутствует параметр ClassLoader
.
Когда код из одного класса запрашивает загрузку другого класса, правильный загрузчик классов для использования - это тот же загрузчик классов, что и вызывающий класс (т. Е. getClass().getClassLoader()
). Так все работает в 99,9% случаев, потому что это то, что JVM делает сама, когда вы впервые создаете экземпляр нового класса, вызываете статический метод или получаете доступ к статическому полю.
Если вы хотите создать класс с использованием отражения (например, при десериализации или загрузке настраиваемого именованного класса), библиотека, выполняющая отражение, должна всегда спрашивать приложение, какой загрузчик классов использовать, получая ClassLoader
как параметр из приложения. Приложение (которое знает все классы, которые необходимо создать) должно передать его getClass().getClassLoader()
.
Любой другой способ получить загрузчик классов неверен. Если библиотека использует такие хаки, как _ 7_, _ 8_ или _ 9_ это ошибка, вызванная недостатком API. По сути, Thread.getContextClassLoader()
существует только потому, что разработчик ObjectInputStream
API забыл принять ClassLoader
в качестве параметра, и эта ошибка не дает покоя сообществу Java по сей день.
Тем не менее, многие классы JDK используют один из нескольких приемов, чтобы угадать, какой загрузчик классов использовать. Некоторые используют ContextClassLoader
(который не работает, когда вы запускаете разные приложения в общем пуле потоков или когда вы покидаете ContextClassLoader null
), некоторые обходят стек (что терпит неудачу, когда прямой вызывающий класс сам является библиотекой), некоторые используют систему загрузчик классов (что нормально, если задокументировано использование только классов в CLASSPATH
) или загрузчик классов начальной загрузки, а некоторые используют непредсказуемую комбинацию вышеперечисленных методов (что только усложняет ситуацию). Это привело к сильному плачу и скрежету зубов.
При использовании такого API сначала попробуйте найти перегрузку метода, который принимает загрузчик классов в качестве параметра. Если разумного метода нет, попробуйте установить ContextClassLoader
перед вызовом API (и затем сбросить его):
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);
}
person
yonran
schedule
25.03.2016