@Required注释如何与JavaConfig一起使用?

时间:2013-05-27 08:40:12

标签: spring annotations required

我是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注释的正确用法吗?

2 个答案:

答案 0 :(得分:8)

在您实例化的bean中设置所需的属性是您自己的责任。处理用@Configuration注释的类中的bean定义的BeanPostProcessor称为ConfigurationClassPostProcessor。处理@Required注释的BeanPostProcessor默认为RequiredAnnotationBeanPostProcessor,在您的配置中使用context:annotation-configcontext: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类编写者和类用户可能是不同的人)。