当前位置: 首页 > 知识库问答 >
问题:

如何找到带有自定义注释@Foo的所有bean?

许兴文
2023-03-14

我有这个spring配置:

@Lazy
@Configuration
public class MyAppConfig {
    @Foo @Bean
    public IFooService service1() { return new SpecialFooServiceImpl(); }
}

如何获取用Foo注释的所有bean的列表?

注意:@Foo是我定义的自定义注释。这不是一个“官方”的Spring注释。

[编辑]根据Avinash T.的建议,我编写了这个测试用例:

import static org.junit.Assert.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import java.lang.annotation.Retention;
import java.lang.reflect.Method;
import java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

public class CustomAnnotationsTest {

    @Test
    public void testFindByAnnotation() throws Exception {

        AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext( CustomAnnotationsSpringCfg.class );

        Method m = CustomAnnotationsSpringCfg.class.getMethod( "a" );
        assertNotNull( m );
        assertNotNull( m.getAnnotation( Foo.class ) );

        BeanDefinition bdf = appContext.getBeanFactory().getBeanDefinition( "a" );
        // Is there a way to list all annotations of bdf?

        Map<String, Object> beans = appContext.getBeansWithAnnotation( Foo.class );
        assertEquals( "[a]", beans.keySet().toString() );
    }


    @Retention( RetentionPolicy.RUNTIME )
    @Target( ElementType.METHOD )
    public static @interface Foo {

    }

    public static class Named {
        private final String name;

        public Named( String name ) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    @Lazy
    @Configuration
    public static class CustomAnnotationsSpringCfg {

        @Foo @Bean public Named a() { return new Named( "a" ); }
             @Bean public Named b() { return new Named( "b" ); }
    }
}

但它失败与org.junit.比较失败:预期:


共有3个答案

傅星光
2023-03-14

在几位Spring专家的帮助下,我找到了一个解决方案:BeanDefinition的源属性可以是AnnotatedTypeMetadata。这个接口有一个方法,我可以用它来获取bean方法的注释:

public List<String> getBeansWithAnnotation( Class<? extends Annotation> type, Predicate<Map<String, Object>> attributeFilter ) {

    List<String> result = Lists.newArrayList();

    ConfigurableListableBeanFactory factory = applicationContext.getBeanFactory();
    for( String name : factory.getBeanDefinitionNames() ) {
        BeanDefinition bd = factory.getBeanDefinition( name );

        if( bd.getSource() instanceof AnnotatedTypeMetadata ) {
            AnnotatedTypeMetadata metadata = (AnnotatedTypeMetadata) bd.getSource();

            Map<String, Object> attributes = metadata.getAnnotationAttributes( type.getName() );
            if( null == attributes ) {
                continue;
            }

            if( attributeFilter.apply( attributes ) ) {
                result.add( name );
            }
        }
    }
    return result;
}

带有助手类和测试用例的完整代码的gist

郑俊弼
2023-03-14

更新:Spring 5.2改变了context.getBeansAuthAnnotion(...)的行为,现在它可以正确处理通过工厂方法创建的bean。所以只需使用它。

原始答案

虽然公认的答案和Grzegorz的答案包含了在所有情况下都适用的方法,但我发现了一个更简单的方法,它在最常见的情况下同样适用。

>

  • 用限定符对Foo进行元注释:

    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface Foo {
    }
    

    将Foo喷洒在工厂方法上,如问题中所述:

    @Foo
    @Bean
    public IFooService service1() {
        return new SpecialFooServiceImpl();
    }
    

    但它也适用于类型级别:

    @Foo
    @Component
    public class EvenMoreSpecialFooServiceImpl { ... }
    

    然后,注入所有由Foo限定的实例,无论其类型和创建方法如何:

    @Autowired
    @Foo
    List<Object> fooBeans; 
    

    然后,fooBeans将包含由带注释的方法(如问题所需)生成的所有实例,或由发现的带注释的类创建的所有实例。

    如果需要,该列表还可以按类型过滤:

    @Autowired
    @Foo
    List<SpecialFooServiceImpl> fooBeans;
    

    好的方面是它不会干扰方法上的任何其他@Qualifier(meta)注释,也不会干扰类型级别上的@Component和其他注释。它也不会在目标bean上强制执行任何特定的名称或类型。

  • 顾俊茂
    2023-03-14

    使用getBeansWithAnnotation()方法获取带有注释的bean。

    Map<String,Object> beans = applicationContext.getBeansWithAnnotation(Foo.class);
    

    下面是类似的讨论。

     类似资料:
    • 问题内容: 我有这个春天的配置: 如何获得所有带有注释的bean的列表? 注意:是我定义的自定义注释。它不是“官方” Spring注释之一。 [编辑]按照Avinash T.的建议,我编写了这个测试案例: 但是失败了。为什么? 问题答案: 一对夫妇spring专家的帮助下,我找到了一个解决方案:的属性可以。这个接口有一个我可以用来获取bean方法的注释的方法:

    • 我有一些这样的豆子: 3)移动将在bins中搜索注释移动到,并将setter添加到: 但是在这个解决方案中,我不喜欢方法。

    • 我已经用自定义注释注释了Spring bean,但似乎Spring在创建bean后删除了我的自定义注释。 第二步不行,我的自定义注释丢失了。(可能是到期的代理文件) 我的豆子 我的一个自定义注释的示例 findAndDoStuffWithAnnotatedThings Bean中出错的内容被传递到一个类,在该类中,我的自定义注释得到验证,但我的验证程序找不到任何注释。(Util使用isAnnota

    • 我目前正在开发一个尽可能尊重六边形架构原则的应用程序。 因此,我的“域”模块(组Id: ; 工件Id:)不依赖于任何技术框架。 我的所有服务都使用自定义注释(本身是我域的一部分)进行注释: 然而,在我的“Quarkus应用”模块(groupId:< code > acme ;artifact id:< code > app-quar kus ,我需要注入我的“域”模块中定义的服务(< code>a

    • 问题内容: 使用基于注释的配置(等)是否可以实现相同的bean继承? http://docs.spring.io/spring/docs/4.1.0.BUILD-SNAPSHOT/spring-framework- reference/htmlsingle/#beans-child-bean- definitions 问题答案: java config中没有抽象bean的概念,因为Java语言已经

    • 使用基于注释的配置(等)是否可以实现相同的bean继承? http://docs.spring.io/spring/docs/4.1.0.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#beans-child-bean-definitions