2012-07-14 1 views
2

В коде моей библиотеки я загружаю имена классов из XML-файла с помощью JAXB, чтобы позже их использовать, используя Class.forName(). Фиктивный пример, чтобы проиллюстрировать случай:Есть ли альтернатива загрузке класса с классом.forName()?

public void libraryMethod() throws Exception { 
    List<String> classNames = loadClassNamesFromXML(); 

    for (String className : classNames) { 
    Class.forName(className).newInstance().doThings(); 
    } 
} 

Теперь, некоторые пользователи используют OSGi настроить свои приложения, и они загружают мою библиотеку с другим загрузчиком классов, чем классы они настраивают, используя мою структуру XML. Это означает, что загрузка может завершиться неудачей, поскольку класс не может быть найден.

Есть ли более надежный способ загрузки таких классов? Или есть ли другой способ настроить эти экземпляры? Я открыт для предложений, которые приводят к этим:

public void libraryMethod() throws Exception { 
    // Spring does things like this: 
    List<SomeType> instances = loadInstancesFromXML(); 

    for (SomeType instance : instances) { 
    instance.doThings(); 
    } 
} 

Некоторые ограничения:

  • из библиотеки точки зрения, жизненный цикл этих случаев не имеет значения. Если у них (пользовательское) состояние, моя библиотека не заметила бы.
  • Я хочу, чтобы в этой библиотеке было все просто, поэтому я хочу, например, избегать создания внешних зависимостей в инфраструктурах конфигурации, таких как spring. Поэтому меня интересуют только решения, которые могут быть достигнуты при использовании стандартных дистрибутивов JDK 6+.
  • Мне бы очень хотелось сохранить простой файл конфигурации XML (небольшие адаптации к структуре XML в порядке).
+1

Вы уже достаточно глубоко в специальном решении, не показывая реальную проблему, которую пытаетесь решить. Можете ли вы объяснить, что делает ваша xml-конфигурация, и почему вы должны загружать классы из других пакетов без импорта своих пакетов? –

+0

@ChristianSchneider: Я пишу библиотеку ([jOOQ] (http://www.jooq.org)). Я не могу импортировать произвольные пользовательские пакеты, но я хотел бы, чтобы пользователи библиотеки могли внедрять реализации «SomeType» в мою библиотеку. С весной было бы довольно легко вводить такие реализации, но это означало бы, что моя библиотека будет иметь «тяжелую» зависимость от самой пружины. –

+0

Проделайте некоторое исследование, прежде чем задавать вопрос, идите для размышления (ленивое посвящение) – Pawan

ответ

4

Если вы хотите, чтобы ваша библиотека была гибкой и работала как в OSGi, так и в среде, отличной от OSGi, вы должны разрешить пользователям предоставлять свои собственные классы ClassLoader или позволить им сообщить вашей библиотеке имена классов, которые у них есть. Прочитано Neil Bartlett blog post.

+0

Нейл - это высшая власть, нет причин чтобы обсудить это дальше :-) Как он завершает, прекратите угадывать. –

1

Драйверы JDBC4 включают META-INF/services/java.sql.Driver в банке, которые используют механизм ServiceProvider для регистрации реализации драйвера с помощью JVM (см. java.util.ServiceLoader javadocs). Наличие драйвера на пути класса автоматически регистрирует драйвер, устраняя необходимость использования Class.forName. Вместо этого код приложения использует ServiceLoader.load для обнаружения зарегистрированных драйверов. Такой же механизм можно использовать для другой конфигурации. Может быть, что-то подобное можно использовать? В стороне, при регистрации собственных реализаций с механизмом поставщика услуг, использование аннотации, такой как spi, выглядит довольно удобно.

+0

Да. ServiceProvider - еще одна сломанная пародия в реестре служб. Однако, если 100% OSGi не является опцией, ServiceProvider все же лучше, чем ничего. Однако это не поможет с загрузчиками классов. –

+0

@IvanDubrov: Интересно. Не могли бы вы объяснить, что такое «проблема загрузки класса», если бы я использовал ServiceProvider? –

+0

Он использует ThreadContext classloader (который нарушен в OSGi) или требует, чтобы вы предоставляли единый загрузчик классов явно, но в OSGi может быть несколько пакетов, предоставляющих службы, и в результате у вас есть несколько загрузчиков классов. –

2

Спасибо за объяснение. Весна не стала бы проще в OSGi. Вы не можете просто ввести класс реализации из пакета, который вы не импортируете. В OSGi вы обычно используете службы OSGi для внедрения реализаций, которые возникают за пределами вашего пакета и неизвестны вам во время компиляции.

Таким образом, ваш пользователь будет реализовывать интерфейс, который вы укажете, и опубликовать его реализацию в качестве службы OSGi. Затем вы можете либо подобрать все такие сервисы, либо дать пользователю указать ldap-фильтр для своей службы в xml-конфигурации.

Преимущество этого подхода заключается в том, что вам не нужно загружать классы и заботиться о загрузчиках классов. Так что это рекомендуется в OSGi. Если вы хотите, чтобы одно и то же решение для внутри и снаружи OSGi Ivan aproach с указанием classloader + classname является альтернативой.

+0

Спасибо за это объяснение. Причина, по которой я думал, что весна может быть решением, заключается в том, что те конкретные пользователи, у которых есть проблемы с jOOQ/OSGi, строят [jOOQ] (http://www.jooq.org) сами и, возможно, исправили его. Но хорошо знать, что это вообще не работает. LDAP звучит как излишний, но услуги могут быть хорошей идеей. Разрешить указывать пользовательский загрузчик классов, по-видимому, является наилучшим вариантом до сих пор, хотя загрузчик контекстного класса @ MarkoTopolnik, похоже, работал как обходной путь. –

+0

При фильтрации для сервисов impls в OSGi вы можете использовать фильтр в синтаксисе LDAP. Это не что-то особенное, доступное во всех инфраструктурах OSGi. Тот, кто публикует эту услугу, может предоставить ее свойства, и тот, кто ищет службу, использует эти фильтры для свойств для поиска. Если вы используете сервис aproach, вам не нужен загрузчик классов, но тогда вы зависите от OSGi. –

2

В общем, в OSGi вы должны воспользоваться услугой. Причина, по которой Class.forName/XML-конфигурация настолько популярна, заключается в том, что только один класс получает контроль. Чтобы настроить остальные, он должен знать классы для инициализации/вызова.

В OSGi эта проблема не существует, поскольку каждый модуль (пакет) (может) получает контроль через декларативные службы (или старомодным способом через активатор). Итак, в OSGi у вас есть одноранговая модель. Любой может зарегистрировать услугу и зависеть от других сервисов.

Таким образом, вместо указания имен классов и предполагая, что они глобально уникальны (они не в больших системах), гораздо проще использовать службы, а не оставлять компилятор Java; эти имена классов очень подвержены ошибкам. В общем, это означает, что вы часто просто регистрируете свою услугу и ожидаете вызова, поскольку нет необходимости инициализировать своих клиентов. Тем не менее, белая доска адрес шаблон ситуация, когда вы хотите узнать о своих клиентах (с bndtools и БНД аннотациями):

«Сервер»

@Component 
public class MyLib { 
    @Reference(type='*') 
    void addSomeType(SomeType st) { 
     st.doThings(); 
    } 
} 

Клиент

@Component 
public class MyClient implements SomeType { 
    public void doThings() { ... } 
} 

Надежда это помогает.

+0

Это интересно. Тем не менее, я бы не хотел вводить так много OSGi в мою библиотеку, так как пользователи библиотеки, которые не используют OSGi, также должны быть в состоянии получить прибыль от этой функциональности ... –

+0

Собственно, глядя на jooq, вы, вероятно, захотите сделать жизнь более модульные и поддерживают шаблон _extender_. В OSGi тривиально отслеживать пучки, которые становятся активными –

Смежные вопросы