通过代码进行 Spring 配置与通过注释进行配置

Posted

技术标签:

【中文标题】通过代码进行 Spring 配置与通过注释进行配置【英文标题】:Spring configuration via code vs. configuration via annotations 【发布时间】:2019-02-14 01:00:54 【问题描述】:

我通过如下代码创建 Spring ApplicationContext:

public static AnnotationConfigWebApplicationContext startContext(String activeProfile,
                              PropertySource<?> propertySource, Class<?>... configs) 
    AnnotationConfigWebApplicationContext result = new AnnotationConfigWebApplicationContext();
    if (propertySource != null) 
        result.getEnvironment().getPropertySources().addLast(propertySource);
    
    if (activeProfile != null) 
        result.getEnvironment().setActiveProfiles(activeProfile);
    
    result.register(configs);
    result.refresh();
    return result;

在测试类中我这样称呼它:

@RunWith(SpringJUnit4ClassRunner.class)
class FunctionalTest 
    private ApplicationContext appContext;

    @BeforeEach
    void init() 
        appContext = Utils.startContext("functionalTest", getPropertySource(), 
                            BaseConfig.class, MyApplication.class, StorageTestConfig.class);
    

它工作正常,没有问题。

现在我正在尝试做同样的事情,但通过注释:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BaseConfig.class, MyApplication.class, StorageTestConfig.class, 
                      loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("functionalTest")
@PropertySource(value = "classpath:test-context.properties")
class FunctionalTest 
      @Autowired
      private ApplicationContext applicationContext;
      ...

这根本不起作用。 applicationContext 不是自动装配的,bean 也是来自配置。你能说我可能做错了吗?

为什么我想从代码切换到注释:我希望能够从配置中自动装配 bean。现在(以上下文创建的代码方式)我应该在测试方法中编写类似appContext.getBean("jdbcTemplate", JdbcTemplate.class) 的内容。如果能写出来就好了

@Autowired
private JdbcTemplate jdbcTemplate;

这将起作用:)

【问题讨论】:

您能否发布一个堆栈跟踪,并在您尝试使用注释时抛出异常? 没有抛出异常,只是没有填充@Autowired字段(ApplicationContext和JdbcTemplate(来自StorageTestConfig类的bean))。它们仍然为空 如何运行测试?你的 JUnit 版本是什么? Junit5,我通过点击运行按钮在 Idea Intellij IDE 中运行测试 【参考方案1】:

您似乎同时使用了两个版本的 JUnit:JUnit 4 和 JUnit 5。 (或者同时使用JUnit4 api和JUnit5 api)

@Test 的注释来自您的FunctionalTest 中的哪里?

org.junit.Test吗?还是org.junit.jupiter.api.Test

好像来自org.junit.jupiter.api.Test

那么你应该使用@ExtendWith(SpringExtension.class 而不是@RunWith(SpringJUnit4ClassRunner.class)

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = BaseConfig.class, Utils.ServConfig.class, Utils.MvcConfig.class, MyApplication.class, StorageTestConfig.class, 
                  loader = AnnotationConfigContextLoader.class)
@ActiveProfiles("functionalTest")
@PropertySource(value = "classpath:test-context.properties")
class FunctionalTest 
      @Autowired
      private ApplicationContext applicationContext;


请注意,SpringExtension5.0 版本起可用。如果你使用低版本,你必须使用JUnit4,用org.junit.Test标记测试方法

在测试类中,我这样称呼它: 它工作正常,没有问题。

@RunWith(SpringJUnit4ClassRunner.class) 在这里毫无价值。您使用 JUnit5 运行此测试。 @RunWith 不考虑。但考虑@BeforeEach。因此它正在工作。

在您的FunctionalTest 中没有考虑注释,因此它不起作用。 使用 JUnit4(@org.junit.Test@RunWith)或 JUnit5(@org.junit.jupiter.api.Test@ExtendWith)。

您似乎同时使用了两个版本的 JUnit:JUnit 4 和 JUnit 5。

如果您不从 JUnit4 迁移到 JUnit 5,请考虑仅使用一个版本的 JUnit。

【讨论】:

谢谢,是的,我在 ExtendWith 上更改了 RunWith,它开始做一些事情 :) 但现在它抛出了我在问题的更新部分中描述的异常。 我认为在Utils.ServConfig 中使用ApplicationContext 而不是AbstractRefreshableWebApplicationContext 会有所帮助。 在我看来是设计问题。您可以将其注入ApplicationContext 并在必要时将其转换为ApplicationContext 的任何子类。请考虑提出一个新问题,因为我们正在讨论的问题超出了最初提出的问题的范围

以上是关于通过代码进行 Spring 配置与通过注释进行配置的主要内容,如果未能解决你的问题,请参考以下文章

Spring 注解配置——@Autowired

Spring注解配置——@Autowired

spring学习

spring boot框架学习学前掌握之重要注解-通过java的配置方式进行配置spring

spring boot框架学习学前掌握之重要注解-通过java的配置方式进行配置spring

Spring IOC容器