【问题标题】:Primary spring bean overridden by ImportResource in Configuration配置中的 ImportResource 覆盖的主 spring bean
【发布时间】:2018-12-13 08:44:57
【问题描述】:

我有一个 Spring 测试配置类,它应该覆盖 xml-config 中现有的 bean。但我的问题是 xml bean 覆盖了在我的测试配置中使用 primary 注释的 bean。我尝试用不同的名称命名测试bean,但这对我也不起作用。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {CamelJmsTest.TestConfig.class})
public class CamelJmsTest {

    @Configuration
    @ImportResource("classpath:production-beans-camel-jms.xml")
    public static class TestConfig {

    @Primary
    @Bean
    public JmsTemplate jmsTemplate() {
        return new JmsTemplate(new ActiveMQConnectionFactory("", "", ACTIVE_MQ_HOST));
    }

    @Primary
    @Bean // ideally i just want this bean to override the bean imported from the xml config
    public RouteConfigBuilder routeConfig() {
        return RouteConfigBuilder.builder().autoStart(true).build();
    }

    @Primary
    @Bean
    public RouteBuilder routeBuilder(@Value("${amq.endpoint}") String endpoint,
                                                              @Autowired Processor processor) {
        return new RouteBuilder(routeConfig(), "", endpoint, processor);
    }
}

    private static final String ACTIVE_MQ_HOST = "vm://activeMQ";

  @BeforeClass
  public static void setActiveMQ() {
    System.setProperty("amq.endpoint", ACTIVE_MQ_HOST);
  } 

  @Autowired
  JmsTemplate jmsTemplate;
  @Test
  public void postJmsMessage() {

    jmsTemplate.send("queue/test", new MessageCreator() {
        @Override
        public Message createMessage(Session session) throws 
     JMSException {
            return session.createTextMessage("Hello World");
        }
    });

    try {
        for (int i = 0; i < 100; i++) {
            Thread.sleep(100);
        }
    } catch (Exception ignored) {
    }
  }
}

这里是相关的xml配置:

<bean id="routeConfig" class="routing.RouteConfigBuilder" init-method="builder">
    <constructor-arg name="redeliveryDelay" value="${<props>.redeliveryDelay}" />
    <constructor-arg name="maximumRedeliveries" value="${<props>.maximumRedeliveries}" />
    <constructor-arg name="autoStart" value="false" />
</bean>

<bean id="routeBuilder" class="routing.RouteBuilder">
    <constructor-arg ref="routeConfig" />
    <constructor-arg name="routeId" value="ROUTE_ID_1"/>
    <constructor-arg name="endpoint" value="${amq.endpoint}" />
    <constructor-arg name="processor" ref="myProcessor" />
</bean>    

这是日志输出。运行测试时:

Overriding bean definition for bean 'routeConfig' with a different 
definition:
  replacing [Root bean: class [null]; scope=; abstract=false; 
  lazyInit=false; autowireMode=3; dependencyCheck=0; 
  autowireCandidate=true; primary=true;
  factoryBeanName=CamelJmsTest.TestConfig; 
  factoryMethodName=routeConfig; initMethodName=null; 
  destroyMethodName=(inferred);
defined in CamelJmsTest]
with [Generic bean: class [RouteConfigBuilder]; scope=; 
 abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;
  autowireCandidate=true; primary=false; factoryBeanName=null; 
  factoryMethodName=null; initMethodName=builder; 
  destroyMethodName=null;
defined in class path resource [production-beans-camel-jms.xml.xml]]

如您所见,我的测试配置中的主 bean 已被覆盖,我想在测试中使用我的测试配置 bean。

我正在使用 Spring 4.3.x。

我已经阅读了很多相关的帖子,但都没有给我答案。任何帮助,将不胜感激。

【问题讨论】:

    标签: java spring dependency-injection integration-testing


    【解决方案1】:

    名称更改似乎适用于我的简化版本。

    我认为这并不重要,但 RouteConfigBuilder 和 RouteBuilder 的构造风格在 Java 和 XML 之间似乎有所不同。

    用 4.3.20 测试

    package com.stackoverflow.q53757986;
    
    import static org.junit.Assert.*;
    
    import org.apache.activemq.ActiveMQConnectionFactory;
    import org.junit.BeforeClass;
    import org.junit.ClassRule;
    import org.junit.Rule;
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ImportResource;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.test.context.junit4.rules.SpringClassRule;
    import org.springframework.test.context.junit4.rules.SpringMethodRule;
    
    @SuppressWarnings("javadoc")
    public class CamelJmsTest {
    
        static final String ACTIVE_MQ_HOST = "vm://activeMQ?broker.persistent=false";
    
        /** The Constant SPRING_CLASS_RULE. */
        @ClassRule
        public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
    
        /** The spring method rule. */
        @Rule
        public final SpringMethodRule springMethodRule = new SpringMethodRule();
    
        @BeforeClass
        public static void setActiveMQ() {
            System.setProperty("amq.endpoint", ACTIVE_MQ_HOST);
        }
    
        @Autowired
        JmsTemplate jmsTemplate;
    
        @Autowired
        RouteConfigBuilder routeConfig;
    
        @Autowired
        RouteBuilder routeBuilder;
    
        @Test
        public void postJmsMessage() {
    
            assertEquals("java", this.routeConfig.source);
            assertEquals("java", this.routeBuilder.source);
    
            this.jmsTemplate.send("queue/test", (MessageCreator) session -> session.createTextMessage("Hello World"));
    
            try {
                for (int i = 0; i < 100; i++) {
                    Thread.sleep(100);
                }
            } catch (Exception ignored) {}
        }
    
        @Configuration
        @ImportResource("classpath:production-beans-camel-jms.xml")
        static class TestConfig {
    
            @Primary
            @Bean
            public JmsTemplate jmsTemplate() {
                return new JmsTemplate(new ActiveMQConnectionFactory("", "", ACTIVE_MQ_HOST));
            }
    
            @Primary
            @Bean // ideally i just want this bean to override the bean imported from the xml config
            public RouteConfigBuilder routeConfig2() {
                return new RouteConfigBuilder("java");
            }
    
            @Primary
            @Bean
            public RouteBuilder routeBuilder2() {
                return new RouteBuilder(routeConfig2(), "java");
            }
        }
        }
    
    <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns = "http://www.springframework.org/schema/beans"
           xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation = "http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
          <bean id="routeConfig"  class="com.stackoverflow.q53757986.RouteConfigBuilder">
            <constructor-arg name="source" value="xml" />
          </bean>
    
          <bean id="routeBuilder"  class="com.stackoverflow.q53757986.RouteBuilder">
            <constructor-arg name="routeConfig" ref="routeConfig" />
            <constructor-arg name="source" value="xml" />
          </bean>
        </beans>   
    

    【讨论】:

    • 我的问题比我想象的要复杂一些。我在 xml 中定义了 3 条骆驼路线。所以我必须在 Java Config 中覆盖 Camels RouteBuilder 的配置方法(并将我的测试 routeconfig 添加到 CamelContext)。我被卡住了,这个答案帮助我解决了我的问题。添加源参数为我提供了所需的信息。谢谢!
    • 没有全貌就很难回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多