Как услуга Java предоставляет API работать?
Вопрос
Кажется, что у всех была неприятная кисть с Java Service Provider, то, что вы можете сделать с файлом, названным как Meta-Inf/Services/com.example.interface, но никто не использует, кроме как попытка загрузить правильный анализатор XML. Я пытаюсь работать с библиотекой, которая использует API поставщика услуг, и обмануть его, чтобы я мог предоставить несколько классов, расширенных во время выполнения (с использованием CGLIB), которые на самом деле не реализуют интерфейс, но можно сделать так легко.
По сути, я думаю, что шаги, которые мне нужно выполнить, являются:
- Создайте пользовательский загрузчик класса, который будет реагировать на GetResources (...) и вернет «дополнительный» URL
- Также есть этот класс погрузчик getresourceasstream (...), чтобы вернуть список классов, которые я собираюсь манипулировать с помощью Cglib, когда его попросят «дополнительный» ресурс
- Наконец, пусть этот класс загружает эти классы по запросу
Но вот где я заблудился. Например, когда библиотека пытается определить, какие есть исполнители, она вызывает getResources (...), что возвращает кучу URL -адресов. Но GetResourCeasStream (...) не принимает URL -адреса, это требует «имен». Имена, которые кажутся относительными в классе, и, следовательно, одинаковые везде. Итак, Meta-Inf/services/com.example.interface в том же «имя», что и Meta-Inf/services/com.example.interface в их банке, верно? За исключением того, что каким -то образом это работает с этими взорванными XML -анализаторами ...
Конечно, все это предполагает, что они были достаточно умными/добрыми, чтобы назвать classloader.getSystemClassloader (), а не использовал ClassLoader.GetSySteMresources (...), ClassLoader.GetSyStemResourCeasStream (...) и т. Д., Как и в последнем случае. Нет возможности зацепить класс -загрузчик и предоставить фальшивый файл.
Я предполагаю, что в этом случае я мог бы использовать BCEL для манипулирования файлами класса, когда мой код упакован Maven, вместо того, чтобы ждать времени выполнения, чтобы сделать это с CGLIB?
Решение
Идея, которую я описал, была на правильном пути. Ошибка, которую я сделал, заключалась в том, чтобы думать, что использование ClassLoader.getResourceAsStream(..)
Чтобы получить доступ к содержимому URL. Вместо этого вы должны просто URL.openStream()
.
Нашел ли я это перед публикацией, java.util.ServiceLoader
(@Since 1.6) дает некоторое представление о том, как правильно делать.