创建@Bean注释bean

时间:2015-09-17 22:32:22

标签: spring spring-boot

我正在开发一个Spring Boot应用程序,并尝试使用基于Java注释的bean创建(使用@Configuration和@Bean),而不是熟悉的旧的基于XML的bean创建。我很困惑。如果我尝试在XML中创建bean但未能设置@Required属性,则在创建应用程序上下文时会出现BeanInitializationException。在我迄今为止的基于注释的bean创建的试验中,尽管情况似乎并非如此。

例如:

public class MyClass {
    ...
    @Required
    public void setSomeProp(String val){
    }
}

然后在Spring XML中:

<bean class="MyClass"/>

这会在应用程序启动期间爆炸(并且IntelliJ会标记它),因为未设置所需的属性。但同样的情况似乎并非如此:

@Configuration
public class MyConfig {
    @Bean
    public MyClass myClass() {
        return new MyClass();
    }
}

即使未设置所需的属性,此应用程序也会正常运行。我必须在这里遗漏一些东西,因为这似乎是Spring中一个非常关键的功能。

更新

我做了一些挖掘工作调试,结果是bean定义被标记为跳过检查@Required字段被设置。在Spring类&#39; RequiredAnnotationBeanPostProcessor&#39;布尔方法&#39; shouldSkip()&#39;对于以这种方式创建的bean,它返回true。当我使用调试器强制该方法返回false bean时,确实爆炸了预期的异常。

看到我正在制作一个非常基本的Spring Boot应用程序,我倾向于(正如Zergleb建议的那样)将其作为错误提交。

更新2 一些进一步的调试显示,即使字段设置强制检查仍然会抛出相同的异常,就好像它没有被设置。所以也许dunni是正确的,并且没有办法使用@Bean表示法。

3 个答案:

答案 0 :(得分:1)

正如你所说,我也无法让@Required按预期运行,这可能是一个错误,需要报告。我还有其他一些对我有用的建议。

使用@Configuration

注释的类
//With the bean set up as usual These all worked
@Bean
public MyClass myClass() {
    return new MyClass();
}

当您注释类@Component并使用组件扫描加载按预期工作时。(组件扫描部分非常重要,您需要@Configuration类来使用@ComponentScan或者删除@Configuration并替换为@SpringBootApplication和this将启用扫描组件而无需使用@Bean配置连接它们

@Component // Added this
public class MyClass {
    ...
    @Required //Failed as expected
    public void setSomeProp(String val){
    }
}

使用@Autowired(required = true)//使用BeanCreationException失败//没有为依赖项找到[java.lang.String]类型的限定bean

//No more @Component
public class MyClass {
    ...
    @Autowired(required=true) //Fails
    public void setSomeProp(String val){
    }
}

@Autowired required = false //不崩溃

public class MyClass {
    ...
    @Autowired(required=false) //Simply never gets called if missing
    public void setSomeProp(String val){
    }
}

@Value //如果缺少test.property则无效//无法解析占位符&#39; test.property&#39;在字符串值&#34; $ {test.property}

public class MyClass {
    @Value("${test.property}")
    String someProp;

    //This getter is not neccesary neither is a setter
    public String getSomeProp() {
        return this.someProp;
    }
}

@Value具有默认值//不崩溃//当调用getSomeProp时,它返回&#34;我的默认值&#34;(除非你的test.property = application.properties文件中的任何内容然后返回& #34;任何&#34;

public class MyClass {
    @Value("${test.property:My Default Value}")
    String someProp;

    //This getter is not neccesary neither is a setter
    public String getSomeProp() {
        return this.someProp; //Returns "My Default Value"
    }
}

如果在myClass方法中找不到任何填充字符串someProp的话,那么@Configuration文件内部也会失败

@Bean
public MyClass myClass(String someProp) { //Fails being unable to populate this arg
    MyClass myObj = new MyClass();
    myObj.setSomeProp(someProp);
    return ;
}

答案 1 :(得分:0)

如果当然这不起作用,因为你自己创建了MyClass的对象(new MyClass()),因此不会评估注释。如果使用@Bean方法创建一个bean,容器只会确保所有依赖项都存在(方法参数)并且遵守bean范围,这意味着它只是一个单独的bean,只有每个应用程序上下文创建一个bean。 bean /对象本身的创建完全由开发人员负责。

xml <bean>标记的等价物用@Component注释类,其中bean完全由容器创建,因此评估注释。

答案 2 :(得分:0)

可以这么说,当您拥有自己的@Configuration类并由其自己创建bean时,@ Required不适用于该类。

如果已经拥有@Component,请让Spring Boot进行组件扫描,并在所需的setter属性中添加@Autowired,它将正常工作。

在网络https://www.boraji.com/spring-required-annotation-example

上找到了此链接

例如:

我有一个名为Employee的组件,具有Id和Name。

@Component
public class Employee {

  int id;
  String name;
  public int getId() {
    return id;
  }
  @Autowired
  @Required
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

}

我有一个名为AppConfig.java的配置类。

@Configuration
public class AppConfig {

  @Bean
  public int getId() {
    return 1;
  }


}

所以现在我们看到,该组件Employee需要在启动期间绑定一个Id属性,因此我编写了Integer类型的bean方法,该方法将在运行时自动连接。如果您未编写Integer类型的Bean,则将导致BeanCreationException。

这是我的主要课程文件。

@SpringBootApplication
public class SingletonApplication {

  public static void main(String[] args) {
    ApplicationContext ctx = 
       SpringApplication.run(SingletonApplication.class, args);

    Employee emp = (Employee)ctx.getBean(Employee.class);
    System.out.println(emp.getId());
  }
}