【问题标题】:How to inject bean of type Supplier?如何注入供应商类型的bean?
【发布时间】:2021-07-22 09:16:41
【问题描述】:

我的代码如下

public class A {
@Inject
private Supplier<Set<String>> set;
.
.
}

我正在为这个类编写测试用例,我的单元测试如下所示:

@Test(groups = "MyApp.unit")
public class ATest extends someOtherClass {

    @Inject
    private A a;

& 我的单位配置看起来像

@Configuration
@Import({someClass.class})
public class UnitTestConfig {
...
 @Bean
    public Supplier<Set<String>> set() {
        Supplier<Set<String>> items = () -> Sets.newHashSet("100");
        return items;
    }

@Bean
    public A a() {
        return new A();
    }


}

我无法将供应商 bean 注入到我的 A 类中。已经放置了调试点并尝试了测试,它进入了 bean 函数,但没有创建供应商类。它给出消息“类没有字段”

所有其他的豆子看起来都很好。有人对此有任何见解吗?

【问题讨论】:

    标签: java spring dependency-injection


    【解决方案1】:

    如果您已经在使用@Configuration 来配置 bean,为什么不使用构造函数注入?

    我建议你重写A类如下:

    public class A {
        private final Supplier<Set<String>> sup;
    
        public A(Supplier<Set<String>> sup) {
            this.sup = sup;
        }
    }
    

    现在您可以使用以下选项之一:

    @Configuration
    public class SampleConfig {
        @Bean
        public Supplier<Set<String>> set () {
            return () -> Set.of("a","b", "c");
        }
    
        @Bean
        public A a (Supplier<Set<String>> sup) {
            return new A(sup);
        }
    }
    

    或者其他方式:

    @Configuration
    public class SampleConfig {
        @Bean
        public Supplier<Set<String>> set () {
            return () -> Set.of("a","b", "c");
        }
    
        @Bean
        public A a () {
            return new A(set());
        }  
    }
    

    在第二个选项中,我将set() 称为常规方法。 Spring 处理带有@Configuration 注释的类,因此它是用于注入的“特殊”调用。 由于供应商是单例,因此多次调用此 set 方法(例如,来自不同的 bean)将返回供应商的相同实例。

    第一种方法更灵活,因为它允许将供应商和 A 类的定义保存在不同的配置文件中,第二种方法假设它们都定义在同一个 @Configuration 中。

    更新(基于 Op 的评论)

    使用字段注入,它的工作原理是一样的:

    public class A {
    
        @Autowired
        private Supplier<Set<String>> sup;
    
        public Set<String> getSet() {
            return this.sup.get();
        }
    
    }
    
    @Configuration
    public class SampleConfig {
        @Bean
        public Supplier<Set<String>> set () {
            return () -> Set.of("a","b", "c");
        }
    
        @Bean
        public A a () {
            return new A();
        }
    
        // this is called right before the application gets started (after all the injections are done - this is just for the sake of illustration)
        @EventListener(ApplicationReadyEvent.class)
        public void onReady(ApplicationReadyEvent evt) {
            A a = evt.getApplicationContext().getBean(A.class);
            System.out.println(a.getSet()); // this will return your set
        }
    }
    

    【讨论】:

    • 应用程序是在没有使用构造函数注入的情况下编写的,并且使用 Inject 注解来注入 bean。除了供应商之外,它似乎对所有其他 bean 都有效。我试图让它在保持应用程序结构的同时保持相同的工作
    • 可能是因为它是一个 lambda,在调试中检查 bean 创建时,它显示 set = {UnitTestConfig$lambda@3808} & 扩展“类没有字段”
    • 使用自动装配(@Autowired@Inject 不管)它的工作原理是一样的。供应商确实没有字段,但是如果您在其上调用“获取”,您将看到您的集合。我已经更新了显示字段注入用例的答案
    • 没有得到你的解决方案,你是说供应商应该被注入?就我而言,它没有。除非它被注入,否则我们不能调用 get() 对吗?
    • 我是说(我也验证了代码 sn-p)供应商像往常一样被注入 - 这里没什么特别的。在它被注入之前,A 类的字段 'sup' 为空,并且不能用它做任何事情。在字段注入的情况下,实际的注入发生在对象被创建之后(在构造函数之后) 从技术上讲,spring 有一个 bean 后处理器。所以你不能在构造函数中对这个字段做任何事情,但是(在应用程序启动后发生的代码中)你可以访问这个字段。由于它是供应商,您只能“获得”它并获得结果,这就是您可以做的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2021-05-05
    • 2019-10-25
    • 1970-01-01
    • 2011-01-10
    相关资源
    最近更新 更多