簡體   English   中英

如何使用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM