简体   繁体   English

Spring 父子关系中带有注释的 Bean 覆盖

[英]Spring Bean override with annotations in parent-child relationship

I have a two classes which are in a parent-child relation, the second one being a mock of the first.我有两个处于父子关系的类,第二个是第一个的模拟。

public class A {
   public void doSomething(){...};
}

public class MockA extends A {
   @Override
   public void doSomething() {...};
}

I also have two @Configuration classes one for development environment and one for test, the test one just mocks a couple of behaviors, but it imports the development one.我还有两个@Configuration 类,一个用于开发环境,一个用于测试,测试一个只是模拟了几个行为,但它导入了开发一个。 Either way, I want that in test environment for MockA to be injected and in development for class A to be injected in other services which autowire it.无论哪种方式,我都希望在测试环境中注入 MockA,并在开发中将 class A 注入其他自动装配的服务中。

I can do that if I overwrite the bean in the test configuration.如果我在测试配置中覆盖 bean,我可以做到这一点。 The following will work:以下将起作用:

@Configuration
public class ApplicationConfig {
@Bean
    public A beanA() {
        return new A();
    }
}

@Configuration
public class TestApplicationConfig {
@Bean
    public A beanA() {
        return new MockA();
    }
}

However, I do not want to create the beans in the @Configuration class.但是,我不想在 @Configuration class 中创建 bean。 I want to put the @Component annotation on each one and let them be injected in services correctly.我想将@Component 注释放在每一个上,并让它们正确地注入服务中。

I've tried two approaches我尝试了两种方法

1) Creating a dummy annotation, adding the annotation on the class A and trying to exclude the bean from the TestApplicationConfig. 1)创建一个虚拟注释,在 class A 上添加注释并尝试从 TestApplicationConfig 中排除 bean。

@Configuration
@ComponentScan(
basePackages = {
        "murex.connectivity.tools.interfaces.monitor.cellcomputer",
        "murex.connectivity.tools.interfaces.monitor"
     }, excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = 
     MyAnnotation.class))
public class TestApplicationConfig {
}

2) using @Component and @Primary annotations on the MockA class. 2) 在 MockA class 上使用 @Component 和 @Primary 注释。 My logic being that in the case both are present (which will happen only on the test case, because only then the MockA is scanned), the MockA will be injected everywhere.我的逻辑是,在两者都存在的情况下(这只会发生在测试用例上,因为只有这样 MockA 才会被扫描),MockA 将被注入到任何地方。 But this does not happen.但这不会发生。

I am wondering if I am doing something wrong or is this a limitation from Spring?我想知道我做错了什么还是这是 Spring 的限制? The @Primary annotation seems to be constructed exactly for this specific case, am I mistaken? @Primary 注释似乎正是针对这种特定情况构建的,我弄错了吗? Is the fact that the two classes have a parent-child relationship that is the problem?这两个类具有父子关系的事实是问题所在吗?

LE Using two different profiles will work. LE 使用两个不同的配置文件将起作用。 I am more curious if my understanding of the two presented approaches is correct and/or if this is a limitation on Spring using @Component annotations如果我对所提出的两种方法的理解是正确的和/或这是否是对使用 @Component 注释的 Spring 的限制,我会更好奇

You can use profiles.您可以使用配置文件。

@Profile("!test")
@Configuration
public class ApplicationConfig {
    @Bean
    public A beanA() {
        return new A();
    }
}

And for test cases: in test resources in application.properties: spring.profiles.active=test or on test class @ActiveProfiles("test") and create configuration:对于测试用例:在 application.properties 的测试资源中: spring.profiles.active=test或测试 class @ActiveProfiles("test")并创建配置:

@Profile("test")
@Configuration
public class TestApplicationConfig {
    @Bean
    public A beanA() {
        return new MockA();
    }
}

Tried to combine two suggested approaches.试图结合两种建议的方法。 It worked for me:它对我有用:

@Component
@Primary
public class ClassA {
    public void doSomething() {
        System.out.println("A");
    }
}

@Component
public class ClassB extends ClassA {
    @Override
    public void doSomething() {
        System.out.println("B");
    }
}

@Component
public class ClassC {
    @Autowired
    public ClassA component;
}

All three classes are in same package.所有三个类都在同一个 package 中。

@Configuration
@ComponentScan(value = "com.test", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
        Primary.class))
public class RandomConfig {


}

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {RandomConfig.class})
public class RandomTest {

    @Autowired
    ClassC c;

    @Test
    void when_then() {
        //prints "B"
        c.component.doSomething();
    }

}

So RandomConfig excludes all @Primary beans, whereas production config uses only @Primary所以RandomConfig排除所有@Primary bean,而生产配置仅使用@Primary

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM