我正在开发一个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类'RequiredAnnotationBeanPostProcessor'中,布尔方法'shouldSkip()'对于以这种方式创建的bean返回true。当我使用调试器强制该方法返回false bean创建时,确实出现了预期的异常。
鉴于我正在制作一个非常基本的Spring Boot应用程序,我倾向于(正如Zergleb建议的)将此作为bug提交。
更新2 进一步的调试表明,即使设置了字段,强制检查仍然会抛出相同的异常,就好像没有设置一样。所以也许dunni是正确的,并且没有办法使用@Bean表示法。
正如你所说,我也无法得到@Required按预期运行,这可能是一个bug,需要报告。我还有其他一些对我有用的建议。
用@Configuration注释的类
//With the bean set up as usual These all worked
@Bean
public MyClass myClass() {
return new MyClass();
}
当你注释了@Component类,并使用组件扫描加载时,效果如预期。(组件扫描部分很重要,你要么需要你的@Configuration类有@ComponentScan,要么删除@Configuration并用@SpringBootApplication代替,这将启用组件扫描,而无需使用@Bean configs连接它们)
@Component // Added this
public class MyClass {
...
@Required //Failed as expected
public void setSomeProp(String val){
}
}
使用@Autowired(required=true)//BeanCreationException失败//没有类型为[java.lang. lang]的合格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。属性丢失//无法解析占位符的测试。${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被调用时,它返回"我的默认值"(除非你有测试。property=应用程序中的任何内容。然后返回"Anything"
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"
}
}
在你的@Configuration文件中,如果找不到任何东西来填充myClass方法中的String someProp,也会失败
@Bean
public MyClass myClass(String someProp) { //Fails being unable to populate this arg
MyClass myObj = new MyClass();
myObj.setSomeProp(someProp);
return ;
}
当然这不起作用,因为您自己创建了MyClass的对象(new MyClass()),因此注释不会被计算。如果使用@Bean
方法创建bean,容器将只确保所有依赖项都在那里(方法参数),并且bean作用域被遵守,这意味着如果它是单例bean,则每个应用程序上下文只创建一个bean。bean/对象本身的创建完全是开发人员的责任。
等价于xml <bean>
标记的是用@Component
注释类,其中bean完全由容器创建,因此注释被求值。
正如所说的,当您拥有自己的@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());
}
}