Сканирование аннотаций Java во время выполнения
каков наилучший способ поиска всего пути к классу для аннотированного класса?
Я делаю библиотеку, и я хочу, чтобы пользователи могли аннотировать свои классы, поэтому при запуске веб-приложения мне нужно сканировать весь путь к классу для определенной аннотации.
вы знаете библиотеку или Java-объект для этого?
редактировать: я думаю о чем-то вроде новой функциональности для Java ее 5 веб-сервисов или EJB это. Аннотировать класс с @WebService или @EJB и система находит эти классы во время загрузки, чтобы они были доступны удаленно.
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
уже слишком поздно отвечать. Я бы сказал, его лучше идти по библиотекам, как 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