Spring Boot 2.1 bean override vs. Primary

15 浏览
0 Comments

Spring Boot 2.1 bean override vs. Primary

Spring Boot 2.1默认禁用了bean覆盖,这是一件好事。然而,我有一些测试用例,其中我使用Mockito替换了一些bean实例。在默认设置下,具有这种配置的测试用例将因为bean覆盖而失败。我发现唯一有效的方法是通过应用程序属性启用bean覆盖:spring.main.allow-bean-definition-overriding=true。然而,我真的希望能够确保我的测试配置中有最少的bean定义设置,这样Spring就会在禁用覆盖时指出。我要覆盖的bean可能是:1. 在另一个配置中定义并导入到我的测试配置中;2. 通过注解扫描自动发现的bean。我原本以为在测试配置中覆盖bean并在其上加上@Primary注解会起作用,就像我们在数据源配置中习惯的那样。然而,这没有任何效果,让我想知道:@Primary注解和禁用的bean覆盖是否矛盾?下面是一个示例:\n

package com.stackoverflow.foo;
@Service
public class AService {
}
package com.stackoverflow.foo;
public class BService {
}
package com.stackoverflow.foo;
@Configuration
public BaseConfiguration {
    @Bean
    @Lazy
    public BService bService() {
        return new BService();
    }
}
package com.stackoverflow.bar;
@Configuration
@Import({BaseConfiguration.class})
public class TestConfiguration {
    @Bean
    public BService bService() {
        return Mockito.mock(BService.class);
    }
}

0
0 Comments

在Spring Boot 2.1中,出现了Bean覆盖与Primary的问题。在测试环境中,我只会将测试所需的bean设置为可用,并且只允许在测试期间进行覆盖,代码如下:

@SpringBootTest
@ActiveProfiles("test")
@TestPropertySource(properties = {"spring.main.allow-bean-definition-overriding=true"})
class FooBarApplicationTests {
  void contextLoads() {}
}

在测试配置中,我模拟了一个bean:

@Configuration
@Profile("test")
public class FooBarApplicationTestConfiguration {
  @Bean
  public SomeBean someBean() {
    return Mockito.mock(SomeBean.class);
  }
}

问题出现的原因是,在Spring Boot 2.1中,允许覆盖bean定义,但是默认情况下禁用了这个功能。因此,需要在测试配置中显式地设置`spring.main.allow-bean-definition-overriding`为`true`,才能允许bean的覆盖。

解决方法就是在测试配置中添加`@TestPropertySource`注解,并设置`spring.main.allow-bean-definition-overriding`为`true`。这样就可以在测试期间覆盖bean定义了。

以上就是关于Spring Boot 2.1中Bean覆盖与Primary问题的原因和解决方法。

0
0 Comments

在Spring Boot 2.1中,bean覆盖和Primary注解之间存在一个问题。当覆盖bean时,上下文中只能有一个具有唯一名称或ID的bean。可以通过以下方式提供两个bean:

package com.stackoverflow.foo;
public class BaseConfiguration {
   public BService bService1() {
       return new BService();
   }
}
package com.stackoverflow.bar;
import com.stackoverflow.foo.BaseConfiguration;
@Import(BaseConfiguration.class)
public class TestConfiguration {
    public BService bService2() {
        return Mockito.mock(BService.class);
    }
}

如果在代码中添加了 `@Autowired` 注解,则默认情况下将注入主要bean:

@Autowired
BService bService;

但是,以上代码对我来说也无效。如果 `BaseConfiguration` 是package-private而不是public的,你可以做什么呢?

0
0 Comments

在Spring Boot 2.1中,出现了一个问题:bean的覆盖和Primary的使用。这个问题的原因是在进行集成测试时,可能需要在某个时候覆盖原有的bean。然而,正确的覆盖实际上是指覆盖具有不同名称的bean,而不是真正的覆盖。

为了实现真正的覆盖(例如使用@Bean@Component注解),在Spring Boot 2.X中需要使用spring.main.allow-bean-definition-overriding=true属性。

然而,对于使用Kotlin Bean Definition DSL的情况,需要注意。在Spring Boot中,它需要一个自定义的ApplicationContextInitializer,如下所示:

class BeansInitializer : ApplicationContextInitializer {

override fun initialize(context: GenericApplicationContext) =

beans.initialize(context)

}

如果你决定通过@TestConfiguration方法在测试中覆盖其中一个基于DSL的bean,那么这种方式将不起作用。因为initializer会在@TestConfiguration方法之后执行,所以在测试中仍然会得到最初的基于DSL的bean。

另一种选择是为你的测试创建一个测试initializer,并在测试属性中列出它们,如下所示(顺序很重要):

context:

initializer:

classes: com.yuranos.BeansInitializer, com.yuranos.TestBeansInitializer

Bean Definition DSL还支持使用bean(isPrimary=true)来指定主要属性,以消除在注入bean时的歧义。然而,如果你完全使用DSL的方式,就不需要使用spring.main.allow-bean-definition-overriding=true

然而,即使使用allow-bean-definition-overriding属性,我的测试bean仍然无法覆盖默认的bean。因此,我将使用(..)的方式来覆盖。

总之,在Spring Boot 2.1.3中,如果你需要覆盖一个bean,可以使用spring.main.allow-bean-definition-overriding=true属性。对于使用Kotlin Bean Definition DSL的情况,需要使用自定义的ApplicationContextInitializer来实现覆盖。

0