我是Spring框架的新手,我在理解@Required
注释和Java配置应用程序时遇到了问题。
这是一个例子。
配置-文件
@Configuration
public class AppConfig {
@Bean
public Movie movieA() {
return new Movie();
}
@Bean
public MovieHolder holder() {
return new MovieHolder();
}
}
MovieHolder.java
public class MovieHolder {
private Movie movie;
public Movie getMovie() {
return movie;
}
@Required
public void setMovie(Movie movie) {
this.movie = movie;
}
}
上下文初始化
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MovieHolder holder = (MovieHolder) context.getBean("holder");
System.out.println("movie: " + holder.getMovie());
据我理解@Required
注释的文档,应该会出现异常,因为电影不是直接设置的,也不是通过自动装配设置的。而是输出movie: null
。
我做错了什么?或者这不是@Required
注释的正确用法吗?
答案 0 :(得分:8)
在您实例化的bean中设置所需的属性是您自己的责任。处理用@Configuration
注释的类中的bean定义的BeanPostProcessor
称为ConfigurationClassPostProcessor
。处理@Required
注释的BeanPostProcessor
默认为RequiredAnnotationBeanPostProcessor
,在您的配置中使用context:annotation-config
和context:component-scan
时默认注册。如果您没有使用这两个标签,您甚至可以将自己的RequiredAnnotationBeanPostProcessor
注册为bean
。
现在,RequiredAnnotationBeanPostProcessor
的默认实现有一个名为boolean shouldSkip(..)
的方法,它检查名为SKIP_REQUIRED_CHECK_ATTRIBUTE
的布尔属性。在RequiredAnnotationBeanPostProcessor
的后处理期间,将为每个bean检查此属性的值。如果它返回false
,则强制执行@Required
约束,否则不执行。{/ p>
现在,ConfigurationClassPostProcessor
在从true
类创建bean定义时将此属性的值设置为@Configuration
(我猜是因为你} 正在定义一个bean,你应该确保它具有所需的属性)。因此,不会对此类bean强制执行@Required
。
顺便说一下,你可能会认为这个SKIP_REQUIRED_CHECK_ATTRIBUTE
属性来自何处以及它在何处设置:它是在BeanDefinition
的实例上设置的,Spring在内部用于创建bean后处理。
如果您确实要强制执行@Required
约束,则必须覆盖RequiredAnnotationBeanPostProcessor
,覆盖boolean shouldSkip(..)
方法并注册此类而不是默认RequiredAnnotationBeanPostProcessor
。正如RequiredAnnotationBeanPostProcessor
的文档所说:
默认的RequiredAnnotationBeanPostProcessor将由“context:annotation-config”和“context:component-scan”XML标记注册。如果要指定自定义RequiredAnnotationBeanPostProcessor bean定义,请删除或关闭默认注释配置。
另一种方法是在initMethod
注释上使用@Bean
属性。哪个可以执行检查以确定所需的属性确实已设置。但是,由于这是基于代码的配置,您也可以自己调用init
方法。
另外,在我看来,使用你自己的RequiredAnnotationBeanPostProcessor
会遇到很多麻烦,正如下面的文档所说:
请注意,'init'方法可能仍然需要实现(并且可能仍然需要),因为此类所做的所有操作都强制实际上已经使用值配置了“required”属性。它不会检查任何其他内容...特别是,它不会检查配置的值是否为空。
因此,总结一下: @Required
默认情况下不适用于@Configuration
个类。如果您需要确保设置了所有属性,那么当您在@Bean
方法中创建bean时(通过调用执行此类验证的某些init
方法),您也可以自己执行此操作,或者只是自己提供所需的属性)。如果确实需要使@Required
注释工作,则需要使用自己的RequiredAnnotationBeanPostProcessor
实现,在spring上下文中将其注册为bean放弃context:annotation-config
的好处。
答案 1 :(得分:1)
尝试使用重写的 shouldSkip()方法声明 @Bean RequiredAnnotationBeanPostProcessor 。
是的,它检查我的bean,但即使我设置了所有必需的属性,它也会失败,即它总是失败 我认为Spring支持Java配置的 @Required 注释存在一个真正的问题,因为当你直接在Java代码中执行时,Spring无法判断你是否设置了属性。 (它之后无法检查' null'字段,因为这意味着要更改 @Required 注释的语义,这应该允许显式设置空值。)
当您使用XML配置时,Spring会创建一个包装器对象来设置属性,因此它可以跟踪所有已配置的' setXxx()'操作。
结论:没有合理的方法为在Java @Configuration 类中创建的bean启用 @Required 注释。
(在我看来,非常不幸的特性,因为bean类编写者和类用户可能是不同的人)。