2008-10-30 5 views
15

Как узнать классы во время выполнения в пути к классам, который реализует определенный интерфейс?Что-то похожее на ServiceLoader в Java 1.5?

ServiceLoader хорошо подходит (я думаю, я его не использовал), но мне нужно сделать это на Java 1.5.

ответ

18

Для этого нет ничего встроенного в 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 выбора вызывающего.

0

Нет надежного способа узнать, какие классы находятся в пути к классам. Согласно его documentation, ServiceLoader полагается на внешние файлы, чтобы рассказать, какие классы загружать; вы можете сделать то же самое. Основная идея состоит в том, чтобы загрузить файл с именем класса (ов) для загрузки, а затем использовать отражение для его создания/им.

1

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

-1

Задумывались ли вы с помощью рамки OSGi?

5

javax.imageio.spi.ServiceRegistry является эквивалентом предыдущих версий Java. Он доступен с Java 1.4.

Это не похоже на общий класс полезности, но это так. Это даже немного более мощный, чем ServiceLoader, так как он позволяет контролировать порядок возвращенных поставщиков и прямой доступ к реестру.

См http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html

1

К сожалению,

Там нет ничего, встроенный в Java 1.5 для этого ...

это только часть правды.

Существует нестандартный sun.misc.Service.

http://www.docjar.com/docs/api/sun/misc/Service.html

Осторожно, это не является частью стандартной J2SE API! Это нестандартная часть Sun JDK. Итак, вы не можете полагаться на это, если используете, скажем, JRockit.

1

Это старый вопрос, но другой вариант заключается в использовании Антенны уровня пакета. См. Мой ответ для: Find Java classes implementing an interface

Аннотации на уровне пакетов - это аннотации, которые содержатся в классах package-info.java.

JAXB использует это вместо сервисных погрузчиков. Я также считаю его более гибким, чем сервисный загрузчик.