Сканирование аннотаций Java во время выполнения



каков наилучший способ поиска всего пути к классу для аннотированного класса?



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



вы знаете библиотеку или Java-объект для этого?



редактировать: я думаю о чем-то вроде новой функциональности для Java ее 5 веб-сервисов или EJB это. Аннотировать класс с @WebService или @EJB и система находит эти классы во время загрузки, чтобы они были доступны удаленно.

725   17  

17 ответов:

использовать орг.springframework.контекст.аннотация.ClassPathScanningCandidateComponentprovider

API

поставщик компонентов, который сканирует путь к классу из базового пакета. Затем он применяет фильтры exclude и include к полученным классам для поиска кандидатов.

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());

и еще одно решение Google reflections.

быстрая комментарий:

  • решение весны путь пойти если вы используете весну. В противном случае это большая зависимость.
  • использование ASM напрямую немного громоздко.
  • использование Java Assist напрямую тоже неуклюже.
  • Annovention супер легкий и удобный. Интеграции maven пока нет.
  • Google reflections тянет в коллекции Google. Индексы все потом очень быстро.

(Edit: FastClasspathScanner теперь переименован в ClassGraph)

попробовать ClassGraph. (Отказ от ответственности, я автор). ClassGraph поддерживает сканирование аннотаций, как во время выполнения, так и во время сборки, но и многое другое. ClassGraph может построить абстрактное представление всего графа класса (все классы, аннотации, методы, параметры метода и поля) в памяти, для всех классов на пути к классам или для классов в пакетах с белым списком, и вы можете запросить этот граф класса, как вы хотите. ClassGraph поддерживает больше механизмов спецификации classpath и загрузчиков классов чем любой другой блок развертки, и также работает плавно с новой системой модуля JPMS, поэтому если вы основываете ваш код на ClassGraph, то ваш код будет maximally портативн. смотрите API здесь.

Если вы хотите действительно легкий вес (без зависимостей, простой API, 15 КБ jar-файл) и очень быстро решение, взгляните на annotation-detector найдено в https://github.com/rmuller/infomas-asl

отказ от ответственности: я автор.

вы можете использовать Java Pluggable Annotation Processing API для записи процессора аннотаций, который будет выполняться во время процесса компиляции и будет собирать все аннотированные классы и создавать индексный файл для использования во время выполнения.

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

вышеуказанный механизм уже реализован в ClassIndex библиотека.

чтобы использовать его аннотировать пользовательские аннотации с @IndexAnnotated мета-аннотаций. Это создаст во время компиляции индексный файл: META-INF/annotations/com/test/YourCustomAnnotation со списком всех аннотированных классов. Вы можете отрыть индекс во время выполнения, выполнив:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

использовать ServiceLoader или реализовать собственные Если вы не в Java 6.

возможно, обработчик аннотаций может создавать необходимые файлы под META-INF/services во время компиляции.

попробовать Scannotation.

Он может быть использован для поиска пути к классам или каталогу lib веб-приложения для конкретных аннотаций.

вы можете использовать http://code.google.com/p/annovention/

немного offtopic, но весна также делает что-то подобное, используя , который вы можете изучать исходный код?

Spring обеспечивает возможность автоматического обнаружения "стереотипных" классов [...]. Для автоматического определения этих классов и регистрации соответствующих компонентов требуется включение элемента [context:component-scan].

С Spring вы также можете просто написать следующее, используя класс AnnotationUtils. т. е.:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

для получения более подробной информации и всех различных методов проверьте официальные документы: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

Я не уверен, что это поможет вам или нет, но вы можете заглянуть в проект apache commons-discovery.

discovery project

уже слишком поздно отвечать. Я бы сказал, его лучше идти по библиотекам, как ClassPathScanningCandidateComponentprovider или как Scannotations

но даже после того, как кто-то хочет попробовать некоторые руки на нем с classLoader, я написал некоторые самостоятельно, чтобы распечатать аннотации из классов в пакете:

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

и в конфигурационном файле, вы ставите имя пакета и unmarshall его в класс .

Java не имеет "Discovery". Единственный способ я знаю, чтобы сканировать каталог .файлы классов должны быть внутри, анализировать имена и использовать это. Ужасно уродливый, может быть, есть лучший пакет в эти дни-я не смотрел в течение нескольких лет.

обычно эта проблема решалась путем включения файла свойств или a .xml-файл с именами классов в нем.

Мне было бы интересно услышать лучший ответ.

API загрузчика классов не имеет метода "перечисления", потому что загрузка класса является активностью "по требованию" - обычно у вас есть тысячи классов в вашем пути к классам, только часть из которых когда-либо понадобится (the rt.jar в настоящее время только 48 МБ!).

Так что, даже если вы может перечислить все классы, это было бы очень много времени и памяти.

простой подход состоит в том, чтобы перечислить соответствующие классы в установочном файле (xml или что угодно, что подходит вашему fancy); если вы хотите сделать это автоматически, ограничьтесь одним JAR или одним каталогом классов.

Google размышления кажется, гораздо быстрее, чем весной. Нашел этот запрос функции, который адресует эту разницу:http://www.opensaga.org/jira/browse/OS-738

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

если вы ищете альтернативу размышления Я хотел бы рекомендовать Panda Utilities-AnnotationsScanner. Это Guava-free (Guava имеет ~3 МБ, Panda Utilities имеет ~200 Кб) сканер на основе исходного кода библиотеки отражений.

Он также предназначен для будущих поисков. Если вы хотите сканировать несколько раз включенные источники или даже предоставить API, который позволяет кому-то сканировать текущий путь к классам, AnnotationsScannerProcess кэширует все за уши ClassFiles, Так что это очень быстро.

простой пример AnnotationsScanner использование:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

Если вы хотите библиотеку Scala, используйте Sclasner: https://github.com/ngocdaothanh/sclasner

Comments

    Ничего не найдено.