@Configuration是强制性的吗?

时间:2018-08-06 13:43:12

标签: spring spring-java-config

在某些情况下,我有一个无法用@Configuration注释的Spring配置类。一开始我以为它无法工作,因为Spring配置必须带有@Configuration注释。但是,在进行了一些测试之后,我才意识到@Configuration不是强制性的。

例如,这是一个不含@Configuration的配置Java类:

public class NotAnnotatedConfiguration {

    @Bean
    public DemoService demoService() {
        return new DemoService();
    }

}

我已尝试在以下测试中加载此配置:

@ContextConfiguration(classes = NotAnnotatedConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class NotAnnotatedConfigurationTest {

    @Autowired DemoService demoService;

    @Test
    public void load() {
        assertNotNull(this.demoService);
    }

}

它有效!在真实的应用程序中,不仅在测试中,我得到相同的结果。

根据我的测试,我认为@Configuration仅在您希望Spring扫描类时才是必需的,否则您可以给Spring提供未注释的配置,它将加载并扫描所有定义的bean在里面。但是,AnnotationConfigApplicationContext的javadoc对我来说似乎不太清楚(可能我误解了):

/**
 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
 * from the given annotated classes and automatically refreshing the context.
 * @param annotatedClasses one or more annotated classes,
 * e.g. {@link Configuration @Configuration} classes
 */
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    register(annotatedClasses);
    refresh();
}

我用测试创建了一个github存储库,以分享我的结论:https://github.com/itelleria/configuration-annotation

问题是,尽管我进行了测试,但是否可以在Spring中不使用@Configuration注释Java配置类?

先谢谢了。

2 个答案:

答案 0 :(得分:1)

我认为您是正确的,Spring将加载config类并创建实例,但不会将实例视为Bean。含义:使用DemoService的其他服务将为每种用法创建多个实例,而不是作为一个单独的实例创建,这是作为bean创建时的默认范围。

public class DemoServiceUsage {

    DemoService demoService;

    public DemoServiceUsage(DemoService demoService) {
        this.demoService = demoService;
    }
}

public class NotAnnotatedConfiguration {
    @Bean
    public DemoService demoService() {
        DemoService demoService = new DemoService();
        System.out.println("demoService " + demoService.hashCode());
        return demoService;
    }

    @Bean
    public DemoServiceUsage demoServiceUsage1() {
        return new DemoServiceUsage(demoService());
    }

    @Bean
    public DemoServiceUsage demoServiceUsage2() {
        return new DemoServiceUsage(demoService());
    }
}

@Configuration
@Import({
    NotAnnotatedConfiguration.class
})
public class ApplicationConfig {
}

@ContextConfiguration(classes = ApplicationConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class NotAnnotatedConfigurationTest {

    @Autowired
    DemoServiceUsage demoServiceUsage1;

    @Autowired
    DemoServiceUsage demoServiceUsage2;

    @Test
    public void load() {
        assertNotNull(this.demoServiceUsage1);
        assertNotNull(this.demoServiceUsage2);
    }
}

在这里,您将看到获得带有不同hashCode的多个demoService输出。如果demoService是一个bean,我们应该只看到一个实例,因为它应该具有单例作用域。

答案 1 :(得分:0)

您的案例可能不需要Configuration,但是首先您可以遵循将类注释为设计的惯例,并且正如您所提到的,当有人进行组件扫描时会出现问题,因为您将需要添加@Component或其他带有元注释的内容:

  

@Configuration使用@Component进行元注释,因此@Configuration类是组件扫描的候选对象

还可以在“配置”中包括组件扫描:

  

@Configuration类不仅可以使用组件扫描来引导,还可以自己使用@ComponentScan注释来配置组件扫描:

 @Configuration
 @ComponentScan("com.acme.app.services")
 public class AppConfig {
     // various @Bean definitions ...
 }