8

我对 Spring Framework 很陌生,在理解@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注释的正确使用吗?

4

2 回答 2

10

在您正在实例化的 bean 中设置所需的属性是您自己的责任。BeanPostProcessor处理带有注释的类中的 bean定义@ConfigurationConfigurationClassPostProcessor. BeanPostProcessor处理您的注释@Required的默认为RequiredAnnotationBeanPostProcessor,在您使用 context:annotation-configcontext:component-scan配置时默认注册。如果您不使用这两个标签,您甚至可以将自己的标签注册RequiredAnnotationBeanPostProcessorbean.

现在, 的默认实现RequiredAnnotationBeanPostProcessor有一个名为的方法boolean shouldSkip(..),用于检查名为 的布尔属性SKIP_REQUIRED_CHECK_ATTRIBUTE。在后处理期间,每个 bean 都会检查此属性的值RequiredAnnotationBeanPostProcessor。如果返回false@Required则强制执行约束,否则不执行。

现在,在从类创建 bean 定义时ConfigurationClassPostProcessor将此属性的值设置为(我猜是因为如果正在定义一个 bean,应该确保它具有所需的属性)。因此,对于此类 bean 不强制执行。true@Configuration@Required

顺便说一句,您可能会认为这个SKIP_REQUIRED_CHECK_ATTRIBUTE属性来自哪里以及它在哪里设置:它是在BeanDefinitionSpring 内部用于 bean 创建和后处理的实例上设置的。

如果您真的想强制执行@Required约束,则必须覆盖RequiredAnnotationBeanPostProcessor,覆盖boolean shouldSkip(..)方法并注册此类而不是默认的RequiredAnnotationBeanPostProcessor. 正如文档RequiredAnnotationBeanPostProcessor所说:

默认的RequiredAnnotationBeanPostProcessor 将由“context:annotation-config”和“context:component-scan”XML 标签注册。如果您打算指定自定义的RequiredAnnotationBeanPostProcessor bean 定义,请删除或关闭默认注释配置。

另一种方法是使用注释initMethod上的属性。@Bean它可以执行检查以查看是否确实设置了所需的属性。但是,由于这是基于代码的配置,您也可以init自己调用该方法。

另外,在我看来,使用自己的 . 遇到很多麻烦并没有多大意义RequiredAnnotationBeanPostProcessor,正如以下文档所述:

请注意,“init”方法可能仍需要实现(并且可能仍然是可取的),因为该类所做的只是强制“必需”属性实际上已配置了一个值。它不检查任何其他内容...特别是,它不检查配置的值是否不为空。

因此,总结一下: @Required默认情况下不适用于@Configuration类。如果您需要确保设置了所有属性,您也可以在@Bean方法中创建 bean 时自己完成(通过调用一些init执行此类验证的方法,或者自己提供所需的属性)。如果你真的需要让@Required注解工作,你需要使用你自己的实现,RequiredAnnotationBeanPostProcessor在spring上下文中将它注册为一个bean并放弃context:annotation-config

于 2013-05-27T12:52:57.887 回答
1

刚刚尝试使用重写的shouldSkip()方法声明@Bean RequiredAnnotationBeanPostProcessor 。

是的,它会检查我的 bean,但即使我设置了所有必需的属性,它也会失败,即它总是失败。我认为 Spring 在支持 Java Config 的@Required
注释 方面存在一个真正的问题,因为当您直接在 Java 代码中执行此操作时,Spring 无法判断您是否设置了该属性。(它不能稍后检查“null”字段,因为这意味着更改@Required注释的语义,该注释应该允许显式设置 null 值)。

当您使用 XML 配置时,Spring 会创建一个包装器对象来设置属性,因此它可以跟踪所有配置的“setXxx()”操作。

结论:没有合理的方法可以为在 Java @Configuration类中创建的 bean 启用@Required注释。 (在我看来,这是一个非常不幸的特性,因为 bean 类编写者和类用户可能是不同的人)。

于 2014-11-05T12:42:19.663 回答