Что-то похожее на ServiceLoader в Java 1.5?
Как мне обнаружить классы во время выполнения в classpath, который реализует определенный интерфейс?
ServiceLoader хорошо подходит (я думаю, я не использовал его), но мне нужно сделать это в Java 1.5.
7 ответов
Для этого нет ничего встроенного в Java 1.5. Я реализовал это сам; это не слишком сложно. Однако при обновлении до Java 6 мне придется заменить вызовы моей реализации вызовами ServiceLoader
, Я мог бы определить небольшой мост между приложением и загрузчиком, но я использую его только в нескольких местах, и сама обертка будет хорошим кандидатом на ServiceLoader.
Это основная идея:
public <S> Iterable<S> load(Class<S> ifc) throws Exception {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
Collection<S> services = new ArrayList<S>();
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream is = url.openStream();
try {
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null)
break;
int comment = line.indexOf('#');
if (comment >= 0)
line = line.substring(0, comment);
String name = line.trim();
if (name.length() == 0)
continue;
Class<?> clz = Class.forName(name, true, ldr);
Class<? extends S> impl = clz.asSubclass(ifc);
Constructor<? extends S> ctor = impl.getConstructor();
S svc = ctor.newInstance();
services.add(svc);
}
}
finally {
is.close();
}
}
return services;
}
Лучшая обработка исключений оставлена читателю в качестве упражнения. Кроме того, метод может быть параметризован для принятия ClassLoader по выбору вызывающей стороны.
javax.imageio.spi.ServiceRegistry
эквивалент с предыдущими версиями Java. Это доступно с Java 1.4.
Это не похоже на общий служебный класс, но это так. Это даже немного мощнее, чем ServiceLoader
, так как это позволяет некоторый контроль над порядком возвращенных провайдеров и прямой доступ к реестру.
См. http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
ServiceLoader довольно прост и используется (неофициально) в JDK с 1.3. ServiceLoader, наконец, сделал его первоклассным гражданином. Он просто ищет файл ресурсов, названный для вашего интерфейса, который в основном находится в каталоге META-INF библиотеки jar.
Этот файл содержит имя класса для загрузки.
Итак, у вас есть файл с именем:
META-INF / услуги /com.example.your.interface
и внутри это одна строка: com.you.your.interfaceImpl.
Вместо ServiceLoader мне нравится Netbeans Lookup. Работает с 1,5 (а может и с 1,4).
Из коробки он делает то же самое, что и ServiceLoader, и его тривиально использовать. Но он предлагает гораздо больше гибкости.
Вот ссылка: http://openide.netbeans.org/lookup/
Вот статья о ServiceLoader, но там внизу упоминается Netbeans Lookup: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
Это старый вопрос, но другой вариант - использовать аннотации на уровне пакета. Смотрите мой ответ для: Найти классы Java, реализующие интерфейс
Аннотации на уровне пакета - это аннотации в классах package-info.java.
JAXB использует это вместо Service Loaders. Я также думаю, что он более гибкий, чем сервисный загрузчик.
К несчастью,
Для этого нет ничего встроенного в Java 1.5...
это только часть правды.
Есть нестандартный sun.misc.Service
вокруг.
http://www.docjar.com/docs/api/sun/misc/Service.html
Осторожно, он не является частью стандартного API J2SE! Это нестандартная часть Sun JDK. Таким образом, вы не можете положиться на это, если вы используете, скажем, JRockit
,
Не существует надежного способа узнать, какие классы находятся в пути к классам. Согласно его документации, ServiceLoader полагается на внешние файлы, чтобы сообщить ему, какие классы загружать; Вы можете сделать то же самое. Основная идея состоит в том, чтобы иметь файл с именем класса (ов) для загрузки, а затем использовать отражение, чтобы создать его / их.