【问题标题】:Create and Autowire the component with constructor使用构造函数创建并自动装配组件
【发布时间】:2022-11-29 03:47:51
【问题描述】:

我有以下课程

@Component
public class MyBean {
    
     private int val1;
    
    

    public MyBean(int val1) {
        this.val1 = val1;
    }

    public int getVal1() {
        return val1;
    }

    public void setVal1(int val1) {
        this.val1 = val1;
    }
    
    
    
    
    
    

}

我想像下面这样自动装配Mybean

@Service
public class MyService
{
    @Autowire
    private MyBean myBean;
}

当我运行时出现以下错误

构造函数 MyBean 的参数 0 需要找不到类型为“int”的 bean。

【问题讨论】:

    标签: java spring-boot spring-boot-configuration


    【解决方案1】:

    当通过构造函数自动装配时,Spring 将每个参数都视为一个 bean。换句话说,如跟踪所示:项目/上下文中不存在 int 类型的 @Bean,因此无法构建 MyBean

    如果你需要MyBean 使用原始 int 初始化,那么你应该在 @Configuration 类中使用 @Bean 注释,这样你就可以传递值。

    @Configuration
    public class MyConfiguration {
    
        @Bean
        public MyBean myBean() { // MyBean must not have @Component annotation
            return new MyBean(1);
        }
     
    }
    

    此外,鉴于该属性已经具有 getter 和 setter,您可以将 val1 的类型更改为 Integer,删除构造函数或声明它时不带参数,并将其值设置为 MyService

    @Component
    public class MyBean {
        
        private Integer val1;
    
        public MyBean() {
            // Empty constructor, might be removed
        }
    
        public int getVal1() {
            return val1;
        }
    
        public void setVal1(int val1) {
            this.val1 = val1;
        }
    
    }
    
    @Service 
    public class MyService { 
    
        @Autowired private MyBean myBean;
    
        /* This method is called AFTER the constructor and dependency injections */
        @PostConstruct
        public void initialize() {
            myBean.setVal1(1);
        }
    
    }
    

    但是,根据用例,MyBean 可以是 POJO,如果您需要使用原始值创建它的话。毕竟,并非 Spring 项目中的每个类都需要是 Bean

    【讨论】:

      【解决方案2】:

      我认为您的错误发生是因为 spring 告诉您它不知道要使用哪个整数值来实例化 Bean MyBean。您可以执行以下操作:

      一个)直接在 bean 中设置默认值并使用无参数构造函数:

      @Component
      public class MyBean {
          
          private int val1 = 1; // or...
          private int val1; // default initialisation to 0
      
          public MyBean() {}
          ...
      }
      

      二)MyBean 提供一个不带参数的默认构造函数,并从属性文件中将值作为属性注入:

      @Component
      public class MyBean {
          
          @Value("${my.property.name}")
          private int val1;
      
          public MyBean() {}
          
          public MyBean(int val1) {
              this.val1 = val1;
          }
          ...
      }
      

      然后在您的根资源目录中,您需要有一个属性文件:

      src/main/resource/application.properties
      

      内容:

      my.property.name=1
      

      在本文中阅读有关属性的更多信息:https://www.baeldung.com/properties-with-spring

      C)可能有许多其他选项……这些将取决于您的具体用例。我们对你的班级以及哪些 int 值是合适的了解不够。

      【讨论】:

        【解决方案3】:

        有很多方法可以实现它,所有这些都会导致将 MyBean 的正确实例注入到 IOC 容器中。

        • 带有注释处理器的 Bean 定义@Configuration

        指示一个类声明一个或多个@Bean 方法,并且可以由 Spring 容器处理以生成 bean 定义。

        @Configuration
        public class Configuration {
            
            @Bean
            MyBean beanName() {
                return new MyBean('some_value');
            }
            
        }
        

        它们有多种访问 IOC 容器本身的方法,直接通过流畅的 api 或通过实现 bean 感知接口(如 InitializingBean)间接访问,如果您在创建 bean 实例后有一些操作,请特别使用它。

        @Configuration
        public class Configuration implements InitializingBean
        {
        
        
            @Bean
            public MyBean beanName() {
                return new MyBean('some_value');
            }
        
            @Override public void afterPropertiesSet() throws Exception
            {
            //some operations
            ...
            }
        }
        

        正如在前面的方法中提到的,这个解决方法是直接访问 IOC 容器,假设您想要 singelton 范围和 MyBean 中的 bean 的规范名称

        ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
        beanFactory.registerSingleton(MyBean, new MyBean('some_value'));
        
        • XMl基础bean装修

        在 Spring 3.0 之前,XML 是定义和配置 bean 的唯一方式,现在已经不再使用了。

        <bean class="{root_path}.Mybean">
            <property name="val1" value="some_value"/>
        </bean>
        

        【讨论】:

          【解决方案4】:

          无参数构造函数

          你需要要么介绍一个无参数MyBean 类中的默认构造函数,Spring 将使用它并且 val1 将具有 0 的值(因为它是 int 类型的默认值)。

          @豆

          或者,您可以在配置类中创建一个带有 @Bean 注释的方法,并通过它提供一个 MyBean 的实例,并提供您需要的 val1 的任何值。

          笔记如果你选择这个选项,你需要消除来自 MyBean 类的 @Component 注释。

          例子:

          @Configuration
          public class MyConfig {
              
              @Bean
              MyBean myBean() {
                  return new MyBean(1_000);
              }
          }
          

          定义多个相同类型的Bean

          还,笔记使用@Bean,您可以根据需要定义任意多种MyBean。另一个优点是 MyBean 不一定是您的域类(它可以来自第三方库或 JDK),而构造型注释只能放在您的自定义类之上。

          这是一个例子:

          @Configuration
          public class BeanConfig {
              
              @Bean
              @Qualifier("1000")
              MyBean myBean1() {
                  return new MyBean(1_000);
              }
              
              @Bean
              @Qualifier("8000")
              MyBean myBean2() {
                  return new MyBean(8_000);
              }
          }
          

          需要@Qualifier注解来区分这些bean。它允许在应用程序的不同部分使用各种风格的 bean。

          让我们在服务中使用值为 8000 的 bean:

          @Service
          public class MyService {
              private MyBean myBean; // field injection is a not a good practice
              
              public MyService(@Qualifier("8000") MyBean myBean) {
                  System.out.println(myBean); // would allow to ditermin which bean is used here (don't forget to override toString)
                  this.myBean = myBean;
              }
          }
          

          笔记不建议在现场使用@Autowired。常见的方法是使用构造函数注入,如果类中只有一个构造函数,则不需要使用 @Autowired

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-03-02
            • 2022-10-24
            • 2013-06-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-22
            相关资源
            最近更新 更多