Java Spring初学者:Beans和配置

4

我正在尝试运行以下类。

package com.example.demo;

import org.apache.catalina.core.ApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {

        var factory = new AnnotationConfigApplicationContext(AppConfig.class);
        test tst = factory.getBean(test.class);
        tst.getDummy().test();
        SpringApplication.run(DemoApplication.class, args);
    }

}

应用程序配置类:

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public test gettest(){
        return new test();
    }
//
    @Bean
    public test2 gettest2(){
        return new test2();
    }
}

第一个测试类:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Component
public class test{
    @Autowired
    test2 dummy;

    public void setDummy(test2 dummy) {
        this.dummy = dummy;
    }

    public test2 getDummy() {
        return dummy;
    }

    void test(){
        System.out.println("test");
    }
}

第二个测试类:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class test2{

    public test2(){

    }
    void test(){
        System.out.println("test2");
    }

}

我在运行时遇到了这个错误

Field dummy in com.example.demo.test required a single bean, but 2 were found:
    - test2: defined in file [/Users/biliuta/IdeaProjects/demo/build/classes/java/main/com/example/demo/test2.class]
    - gettest2: defined by method 'gettest2' in class path resource [com/example/demo/AppConfig.class]

如果我在 AppConfig 中注释掉 public test2 gettest2() bean,就会出现以下错误:

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'gettest': Unsatisfied dependency expressed through field 'dummy'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.test2' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

为什么在第一个例子中可以找到test2 bean,但是当我从AppConfig中注释掉它时,就无法再找到它了(在第一个错误消息中,你可以清楚地看到test2已经被找到了)?@Configure注解是否是将bean添加到上下文中的必要条件?
3个回答

4

当您定义 @Component 时,您定义了一个可以被自动装配找到的bean。

当您在 `@Configuration` 中定义 @Bean 时,您定义了一个可以被自动装配找到的bean。

因此,您定义了两次相同的bean,这会导致Spring无法知道哪个是正确的bean进行自动装配。

解决方案是只定义一次。


1
有几种方法可以让你的类成为Spring / Spring Boot中的bean:
  • 使用@Component或任何其他派生注释(@Service, @Repository, @Controller, @RestController)对你的类进行注释。
  • 在XML配置中定义你的类作为一个bean
  • 使用@Bean注释(这个只能应用于方法,指定它返回一个由Spring上下文管理的bean)。通常在Configuration类方法中声明@Bean注释。
当Spring初始化其上下文时,它会查找任何bean定义并创建bean。在你的情况下,它发现了testtest2的重复声明,因此你需要删除你的配置类或从你的类中删除@Component注释。
更多信息请参见Spring Bean documentation

如果我删除配置类,那么在main()函数中我需要使用哪个bean工厂,而不是AnnotationConfigApplicationContext(AppConfig.class)?是否有一个默认的工厂可以收集包中的所有bean? - user1934513
从类中删除@Component注释是有效的。 - user1934513
AnnotationConfigApplicationContext(test.class, test2.class) 注解配置应用上下文(test.class,test2.class) - user1934513
哦,我没有注意到你正在创建一个应用程序上下文。你可以注入上下文(这真的不是一个好主意),或者只是摆脱这些bean,但保留配置。 - vcmkrtchyan

1
如何使用@Autowired:它首先尝试通过类型查找所需的bean,如果有多个相同类型的bean,则使用备用机制按bean名称查找。

但是,当您从AppConfig禁用@Bean注释时,应该至少有一个类型为Test2的bean,因为您已经使用@Component注释对Test2进行了注释,但它找不到。要解决此问题,您需要在AppConfig类中添加@ComponentScan(basePackageClasses = { Test2.class }),如下所示。
@Configuration
@ComponentScan(basePackageClasses = { Test2.class })
public class AppConfig {
@Bean
public Test gettest(){
    return new Test();
}

//@Bean
public Test2 gettest2(){
    return new Test2();
}
}

但是,如果您按照以下方式启用bean注释。
@Configuration
@ComponentScan(basePackageClasses = { Test2.class })
public class AppConfig {
@Bean
public Test gettest(){
    return new Test();
}

@Bean
public Test2 gettest2(){
    return new Test2();
}
}

您需要通过使用来更改Test上Test2的注入

 @Autowired
 Test2 test2;

或者通过使用。
 @Autowired
 Test2 gettest2;

是的,这解决了问题,但这不是我不理解的。当涉及到Spring如何管理bean时,我更缺乏整体思路。帖子末尾的问题是,如果我注释掉AppConfig中的public test2 gettest2()方法,为什么无法再找到test2 bean。 - user1934513
现在回答您的问题了吗,@user1934513? - Tanmoy Majumdar
是的。使用ComponentScan很有意义。谢谢。 - user1934513

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接