![](/img/trans.png)
[英]Can't return all classes marked with specific annotation using spring ClassPathScanningCandidateComponentProvider
[英]How to find interfaces with specified annotation using ClassPathScanningCandidateComponentProvider?
我嘗試用 org.springframework:spring-context 和ClassPathScanningCandidateComponentProvider
替換 org.reflections:reflections 庫,因為反射庫有一個對我來說至關重要的錯誤。 我想找到所有包含特定注釋的類、接口和子類。 反思很容易:
var subTypeScanner = new SubTypesScanner( true );
var typeAnnotationScanner = new TypeAnnotationsScanner();
var configBuilder = new ConfigurationBuilder().setUrls( ClasspathHelper.forPackage( "com.example" ) )
.setScanners( subTypeScanner, typeAnnotationScanner );
Reflections reflections= new Reflections( configBuilder );
Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Path.class);
不幸的是,使用ClassPathScanningCandidateComponentProvider
對我來說並不容易。 我已經解決了尋找子類的方法。 首先,我找到一組類,然后分別為每個 class 搜索子類:
protected Set< Class< ? > > findClasses( ClassPathScanningCandidateComponentProvider aScanner )
{
return aScanner.findCandidateComponents( "com.example" )
.stream()
.map( BeanDefinition::getBeanClassName )
.map( e -> {
try
{
return Class.forName( e );
}
catch( ClassNotFoundException aE )
{
throw new RuntimeException( aE );
}
} )
.collect( Collectors.toUnmodifiableSet() );
}
protected Set< Class< ? > > findSubClasses( Set< Class< ? > > aClasses )
{
return aClasses.stream()
.map( aClass -> {
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider( false );
scanner.addIncludeFilter( new AssignableTypeFilter( aClass ) );
return scanner.findCandidateComponents( "com.example" );
} )
.flatMap(Collection::stream)
.map( BeanDefinition::getBeanClassName )
.map( e -> {
try
{
return Class.forName( e );
}
catch( ClassNotFoundException aE )
{
throw new RuntimeException( aE );
}
} )
.collect( Collectors.toUnmodifiableSet() );
}
不幸的是,我不知道如何找到帶有注釋的接口。 以下代碼找不到接口。 它只查找具有Path
注釋或擴展 class 或實現具有Path
注釋的接口的類。
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider( false );
scanner.addIncludeFilter( new AnnotationTypeFilter( Path.class, true, true ) );
Set<Class<?>> classes = findClasses(scanner);
//findSubClasses(findClasses( scanner ))
如何找到帶有Path
注釋的接口?
當前的實現也很清楚,如方法級別文檔中所述
默認實現檢查 class 是否不是接口並且不依賴於封閉的 class。
根據這個 github 問題,我們可以通過覆蓋isCandidateComponent()
方法的行為來解決這個問題
這是來自 github 問題的示例參考工作代碼
provider = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) || beanDefinition.getMetadata().isAbstract();
}
};
注解
package in.silentsudo.classpathannotationscanner.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyCustomAnnotation {
}
我的簡單界面
package in.silentsudo.classpathannotationscanner;
import in.silentsudo.classpathannotationscanner.annotation.MyCustomAnnotation;
@MyCustomAnnotation
public interface SimpleInterface {
}
示例測試代碼
package in.silentsudo.classpathannotationscanner;
import in.silentsudo.classpathannotationscanner.annotation.MyCustomAnnotation;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RestController
@RequestMapping("/list")
public class SampleController {
private final ClassPathScanningCandidateComponentProvider provider;
SampleController() {
provider = new ClassPathScanningCandidateComponentProvider(false) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) || beanDefinition.getMetadata().isAbstract();
}
};
provider.addIncludeFilter(new AnnotationTypeFilter(MyCustomAnnotation.class, true, true));
}
@GetMapping
public Map<String, Object> list() throws Exception {
return Map.of("mycustomannotationsmarkedinterafce", getData());
}
public List<String> getData() throws Exception {
final Set<BeanDefinition> classes = provider.findCandidateComponents("in.silentsudo.classpathannotationscanner");
List<String> names = new ArrayList<>();
for (BeanDefinition bean : classes) {
Class<?> clazz = Class.forName(bean.getBeanClassName());
names.add(clazz.getName());
}
return names;
}
}
這應該給出以下響應:
{
"mycustomannotationsmarkedinterafce": [
"in.silentsudo.classpathannotationscanner.SimpleInterface"
]
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.