Jaki jest najlepszy sposób przeszukiwania całej ścieżki klasy dla klasy z adnotacjami?
Robię bibliotekę i chcę pozwolić użytkownikom na dodawanie adnotacji do swoich klas, więc kiedy uruchomi się aplikacja sieci Web, muszę przeskanować całą ścieżkę klasy w poszukiwaniu określonych adnotacji.
Czy znasz bibliotekę lub narzędzie Java, aby to zrobić?
Edycja: Myślę o czymś takim, jak nowa funkcjonalność Java EE 5 Web Services lub EJB. Adnotujesz swoją klasę za pomocą @WebService
lub, @EJB
a system znajduje te klasy podczas ładowania, aby były dostępne zdalnie.
źródło
@Conditional
adnotacji. Jeśli więc klasa ma@Conditional
wartość false, nie zostanie zwróconafindCandidateComponents
, nawet jeśli pasuje do filtra skanera. To mnie dzisiaj rzuciło - zamiast tego skorzystałem z rozwiązania Jonathana poniżej.BeanDefinition
obiekt nie zapewnia bezpośredniego pobrania klasy. Wydaje się, że najbliższe jestgetBeanClassName
zwrócenie w pełni kwalifikowanej nazwy klasy, ale dokładne zachowanie tej metody nie jest jasne. Ponadto nie jest jasne, w którym module ładującym została znaleziona klasa.Class<?> cl = Class.forName(beanDef.getBeanClassName());
farenda.com/spring/find-annotated-classesInnym rozwiązaniem są odbicia Google .
Szybki przegląd:
źródło
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)
. co ty.Możesz znaleźć klasy z dowolną adnotacją za pomocą ClassGraph , a także wyszukać inne kryteria zainteresowania, np. Klasy, które implementują dany interfejs. (Oświadczenie, jestem autorem ClassGraph.) ClassGraph może zbudować abstrakcyjną reprezentację całego wykresu klas (wszystkich klas, adnotacji, metod, parametrów metod i pól) w pamięci, dla wszystkich klas na ścieżce klas lub dla klas w pakiety umieszczone na białej liście i możesz wyszukiwać wykresy klas w dowolny sposób. ClassGraph obsługuje więcej mechanizmów specyfikacji ścieżek klas i programów ładujących klasy niż jakikolwiek inny skaner, a także bezproblemowo współpracuje z nowym systemem modułów JPMS, więc jeśli oprzesz swój kod na ClassGraph, Twój kod będzie maksymalnie przenośny. Zobacz API tutaj.
źródło
Reflections
. Ponadto, jeśli używasz guava / etc i chcesz zmienić kolekcje, proste jak ciasto. Świetne komentarze również w środku.Jeśli chcesz naprawdę lekkiej wagi (brak zależności, prosty interfejs API, plik jar 15 kb) i bardzo szybkiego rozwiązania, spójrz
annotation-detector
na stronę https://github.com/rmuller/infomas-aslOświadczenie: Jestem autorem.
źródło
Za pomocą interfejsu API Java Pluggable Annotation Processing API można napisać procesor adnotacji, który zostanie wykonany podczas procesu kompilacji i zgromadzi wszystkie klasy adnotacji i zbuduje plik indeksu na potrzeby środowiska wykonawczego.
Jest to najszybszy możliwy sposób na wykrycie klasy z adnotacjami, ponieważ nie trzeba skanować ścieżki klasy w czasie wykonywania, co zwykle jest bardzo powolne. To podejście działa również z dowolnym modułem ładującym klasy, a nie tylko z URLClassLoaders zwykle obsługiwanym przez skanery środowiska wykonawczego.
Powyższy mechanizm jest już zaimplementowany w bibliotece ClassIndex .
Aby z niego skorzystać, dodaj adnotację niestandardową za pomocą meta-adnotacji @IndexAnnotated . W czasie kompilacji zostanie utworzony plik indeksu: META-INF / annotations / com / test / YourCustomAnnotation zawierający wszystkie klasy z adnotacjami. Dostęp do indeksu można uzyskać w czasie wykonywania, wykonując:
źródło
Czy jest już za późno na odpowiedź? Powiedziałbym, że lepiej, aby przejść przez biblioteki jak ClassPathScanningCandidateComponentProvider lub jak Scannotations
Ale nawet po tym, jak ktoś chce spróbować z ClassLoaderem, napisałem sam, aby wydrukować adnotacje z zajęć w pakiecie:
A w pliku konfiguracyjnym umieścisz nazwę pakietu i rozpakujesz go do klasy.
źródło
Za pomocą Spring możesz także napisać poniższe, używając klasy AnnotationUtils. to znaczy:
Aby uzyskać więcej informacji i wszystkie różne metody, sprawdź oficjalne dokumenty: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html
źródło
null
wartość jako drugi parametr (który definiuje klasę, w której hierarchia dziedziczenia Spring będzie skanować w poszukiwaniu klasy, która korzysta z adnotacji), zawsze otrzymasznull
zwrot, zgodnie z implementacją.Jest wspaniały komentarz zapp, który tonie we wszystkich tych odpowiedziach:
źródło
Interfejs API Classloader nie ma metody „wyliczania”, ponieważ ładowanie klas jest działaniem „na żądanie” - zwykle w ścieżce klasy znajdują się tysiące klas, z których tylko część będzie kiedykolwiek potrzebna (rt.jar sam jest obecnie 48 MB!).
Tak więc, nawet jeśli można wyliczyć wszystkie klasy, zajęłoby to dużo czasu i pamięci.
Proste podejście polega na wypisaniu odpowiednich klas w pliku instalacyjnym (xml lub cokolwiek, co pasuje do twoich upodobań); jeśli chcesz to zrobić automatycznie, ogranicz się do jednego katalogu JAR lub jednego katalogu klas.
źródło
Google Reflection, jeśli chcesz odkryć również interfejsy.
Wiosna
ClassPathScanningCandidateComponentProvider
nie odkrywa interfejsów.źródło
Google Reflections wydaje się być znacznie szybszy niż Spring. Znaleziono to żądanie funkcji uwzględniające tę różnicę: http://www.opensaga.org/jira/browse/OS-738
Jest to powód, aby używać Reflections, ponieważ czas uruchamiania mojej aplikacji jest naprawdę ważny podczas programowania. Refleksje wydają się również bardzo łatwe w użyciu w moim przypadku użycia (znajdź wszystkich implementatorów interfejsu).
źródło
Jeśli szukasz alternatywy dla odbić , chciałbym polecić Panda Utilities - AnnotationsScanner . Jest to skaner bez Guawy (Guava ma ~ 3 MB, Panda Utilities ma ~ 200kb) skaner oparty na kodzie źródłowym biblioteki odbić.
Jest również dedykowany do wyszukiwania w przyszłości. Jeśli chcesz skanować wielokrotnie dołączone źródła lub nawet udostępnić interfejs API, który pozwala komuś skanować bieżącą ścieżkę klasy,
AnnotationsScannerProcess
buforuje wszystkie pobrane plikiClassFiles
, więc jest to naprawdę szybkie.Prosty przykład
AnnotationsScanner
użycia:źródło
Wiosna ma coś, co nazywa się
AnnotatedTypeScanner
klasą.Ta klasa używa wewnętrznie
Ta klasa ma kod do rzeczywistego skanowania ścieżki klasy zasobów . Robi to za pomocą metadanych klasy dostępnych w czasie wykonywania.
Można po prostu rozszerzyć tę klasę lub użyć tej samej klasy do skanowania. Poniżej znajduje się definicja konstruktora.
źródło