런타임시 Java 주석 스캔
주석이 달린 클래스의 전체 클래스 경로를 검색하는 가장 좋은 방법은 무엇입니까?
라이브러리를 만들고 있는데 사용자가 클래스에 주석을 달도록 허용하고 싶습니다. 따라서 웹 응용 프로그램이 시작될 때 특정 주석에 대해 전체 클래스 경로를 스캔해야합니다.
이 작업을 수행 할 라이브러리 또는 Java 기능을 알고 있습니까?
편집 : Java EE 5 웹 서비스 또는 EJB의 새로운 기능과 같은 것을 생각하고 있습니다. 당신은 당신의 클래스에 주석 @WebService
또는 @EJB
그들이 원격으로 액세스 할 수있는 로딩 그렇게하는 동안 시스템은 이러한 클래스를 찾습니다.
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider를 사용하십시오.
API
기본 패키지에서 클래스 경로를 스캔하는 구성 요소 제공자. 그런 다음 후보를 찾기 위해 결과 클래스에 제외 및 포함 필터를 적용합니다.
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());
또 다른 해결책은 구글 반영 입니다.
빠른 검토:
- Spring 솔루션은 Spring을 사용하는 경우 갈 수있는 방법입니다. 그렇지 않으면 큰 의존성입니다.
- ASM을 직접 사용하는 것은 다소 번거 롭습니다.
- Java Assist를 직접 사용하는 것도 복잡합니다.
- Annovention은 매우 가볍고 편리합니다. 아직 maven 통합이 없습니다.
- Google 리플렉션은 Google 컬렉션을 끌어냅니다. 모든 것을 색인화 한 다음 매우 빠릅니다.
ClassGraph를 사용하여 주어진 주석이있는 클래스를 찾을 수있을 뿐만 아니라 다른 관심있는 기준 (예 : 주어진 인터페이스를 구현하는 클래스)을 검색 할 수도 있습니다. (면책 조항, 나는 ClassGraph의 저자입니다.) ClassGraph는 전체 클래스 그래프 (모든 클래스, 주석, 메소드, 메소드 매개 변수 및 필드)를 메모리, 클래스 경로의 모든 클래스 또는 클래스의 추상 표현을 작성할 수 있습니다 허용 된 패키지를 사용하면 원하는 클래스 그래프를 쿼리 할 수 있습니다. ClassGraph는 다른 스캐너보다 더 많은 클래스 경로 지정 메커니즘 및 클래스 로더를 지원 하며 새로운 JPMS 모듈 시스템과도 완벽하게 작동하므로 ClassGraph를 기반으로 코드를 작성하면 코드를 최대한 이식 할 수 있습니다. 여기 API를 참조하십시오.
정말 가볍고 (종속성, 간단한 API, 15kb jar 파일) 매우 빠른 솔루션 을 원한다면 https://github.com/rmuller/infomas-asl 에서 annotation-detector
찾아 보십시오.
면책 조항 : 나는 저자입니다.
Java Pluggable Annotation Processing API를 사용하여 컴파일 프로세스 중에 실행될 주석 프로세서를 작성하고 주석이 달린 모든 클래스를 수집하고 런타임에 사용할 색인 파일을 빌드 할 수 있습니다.
런타임에 클래스 경로를 스캔 할 필요가 없기 때문에 어노테이션이있는 클래스 발견을 수행 할 수있는 가장 빠른 방법입니다. 이는 일반적으로 매우 느린 조작입니다. 또한이 방법은 모든 클래스 로더에서 작동하며 일반적으로 런타임 스캐너에서 지원하는 URLClassLoader와 함께 작동합니다.
위의 메커니즘은 이미 ClassIndex 라이브러리 에서 구현되었습니다 .
이를 사용하려면 @IndexAnnotated 메타 주석으로 사용자 정의 주석에 주석을 달 수 있습니다 . 이렇게하면 컴파일시 색인 파일 인 META-INF / annotations / com / test / YourCustomAnnotation이 주석이 달린 모든 클래스를 나열합니다. 다음을 실행하여 런타임시 색인에 액세스 할 수 있습니다.
ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
Scannotation을 시도 하십시오 .
특정 주석에 대한 클래스 경로 또는 웹 애플리케이션 lib 디렉토리를 검색하는 데 사용할 수 있습니다.
http://code.google.com/p/annovention/ 을 사용할 수 있습니다 .
약간의 주제는 아니지만 Spring은 <context : component-scan>을 사용하여 비슷한 것을 수행합니다. 소스 코드를 연구 할 수 있습니까?
Spring은 'stereotyped'클래스를 자동으로 감지하는 기능을 제공합니다 [...]. 이러한 클래스를 자동 감지하고 해당 Bean을 등록하려면 [context : component-scan element]가 포함되어야합니다.
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;
}
}
그리고 구성 파일에서 패키지 이름을 넣고 클래스에 정렬 해제하십시오.
클래스 로딩은 "주문형"활동이기 때문에 Classloader API에는 "열거"메소드가 없습니다. 일반적으로 클래스 경로에 수천 개의 클래스가 있으며 그 중 일부만 필요합니다 (rt.jar 현재는 48MB입니다!).
따라서 모든 클래스를 열거 할 수 있더라도 시간과 메모리가 많이 소모됩니다.
간단한 접근 방식은 관련 클래스를 설정 파일 (xml 또는 원하는대로)에 나열하는 것입니다. 이를 자동으로 수행하려면 하나의 JAR 또는 하나의 클래스 디렉토리로 제한하십시오.
그것이 도움이 될지 확실하지 않지만 아파치 공통점 발견 프로젝트를 살펴볼 수 있습니다.
Google Reflections 는 Spring보다 훨씬 빠릅니다. 이 차이점을 해결하는이 기능 요청을 찾았습니다. http://www.opensaga.org/jira/browse/OS-738
이것이 개발 중에 내 응용 프로그램의 시작 시간이 정말로 중요하기 때문에 Reflections를 사용하는 이유입니다. 리플렉션도 내 유스 케이스에 매우 사용하기 쉬운 것 같습니다 (인터페이스의 모든 구현자를 찾으십시오).
반사 에 대한 대안을 찾고 있다면 Panda Utilities-AnnotationsScanner 를 추천 합니다. 리플렉션 라이브러리 소스 코드를 기반으로하는 Guava-free (Guava는 ~ 3MB, Panda Utilities는 ~ 200kb) 스캐너입니다.
또한 미래 기반 검색 전용입니다. 포함 된 소스를 여러 번 스캔하거나 누군가가 현재 클래스 경로를 스캔 할 수있는 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);
인터페이스도 찾고 싶다면 Google Reflection을 사용하십시오.
Spring ClassPathScanningCandidateComponentProvider
이 인터페이스를 감지하지 않습니다.
Spring에는 AnnotatedTypeScanner
클래스 라는 것이 있습니다.
이 클래스는 내부적으로
ClassPathScanningCandidateComponentProvider
이 클래스에는 클래스 경로 리소스 를 실제로 검색하기위한 코드가 있습니다. 런타임시 사용 가능한 클래스 메타 데이터를 사용하여이를 수행합니다.
이 클래스를 단순히 확장하거나 스캔에 동일한 클래스를 사용할 수 있습니다. 아래는 생성자 정의입니다.
/**
* Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
*
* @param considerInterfaces whether to consider interfaces as well.
* @param annotationTypes the annotations to scan for.
*/
public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {
this.annotationTypess = Arrays.asList(annotationTypes);
this.considerInterfaces = considerInterfaces;
}
Scala 라이브러리를 원한다면 Sclasner를 사용하십시오 : https://github.com/ngocdaothanh/sclasner
참고 URL : https://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime
'Programing' 카테고리의 다른 글
JavaScript에서 문자열을 부동 소수점으로 변환하는 방법은 무엇입니까? (0) | 2020.04.10 |
---|---|
힘내 수정, 삭제 및 추적되지 않은 모든 파일을 추가 하시겠습니까? (0) | 2020.04.10 |
ffmpeg, libav 및 avconv의 차이점과 유사점은 무엇입니까? (0) | 2020.04.10 |
기존 Eclipse 프로젝트를 Maven 프로젝트로 변환 (0) | 2020.04.10 |
Java에서 배열의 일부만 가져 옵니까? (0) | 2020.04.10 |