繁体   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