2016-06-03 1 views
2

프로덕션 애플리케이션 중 하나에서 다소 복잡한 스프링 통합 -amqp 사용 사례가 발생했으며 시작시 "org.springframework.integration.MessageDispatchingException : Dispatcher에 구독자가 없습니다"예외가 발생했습니다. 시작시 초기 오류가 발생하면 동일한 구성 요소에서 예외가 더 이상 표시되지 않습니다. 이것은 AMQP 아웃 바운드 어댑터에 의존하는 구성 요소에 대한 일종의 시작 경쟁 조건과 같아서 수명주기의 초기에 사용하게됩니다.스프링 통합 amqp 아웃 바운드 어댑터 경쟁 조건?

PostConstruct 메서드에서 아웃 바운드 어댑터에 연결된 채널로 보내는 게이트웨이를 호출하여이를 재현 할 수 있습니다.

설정 :

package gadams; 

import org.springframework.amqp.core.Queue; 
import org.springframework.amqp.rabbit.core.RabbitTemplate; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.Bean; 
import org.springframework.integration.annotation.IntegrationComponentScan; 
import org.springframework.integration.dsl.IntegrationFlow; 
import org.springframework.integration.dsl.IntegrationFlows; 
import org.springframework.integration.dsl.amqp.Amqp; 
import org.springframework.integration.dsl.channel.MessageChannels; 
import org.springframework.messaging.MessageChannel; 

@SpringBootApplication 
@IntegrationComponentScan 
public class RabbitRace { 

    public static void main(String[] args) { 
     SpringApplication.run(RabbitRace.class, args); 
    } 

    @Bean(name = "HelloOut") 
    public MessageChannel channelHelloOut() { 
     return MessageChannels.direct().get(); 
    } 

    @Bean 
    public Queue queueHello() { 
     return new Queue("hello.q"); 
    } 

    @Bean(name = "helloOutFlow") 
    public IntegrationFlow flowHelloOutToRabbit(RabbitTemplate rabbitTemplate) { 
     return IntegrationFlows.from("HelloOut").handle(Amqp.outboundAdapter(rabbitTemplate).routingKey("hello.q")) 
       .get(); 
    } 

} 

게이트웨이 :

package gadams; 

import org.springframework.integration.annotation.Gateway; 
import org.springframework.integration.annotation.MessagingGateway; 

@MessagingGateway 
public interface HelloGateway { 

    @Gateway(requestChannel = "HelloOut") 
    void sendMessage(String message); 
} 

구성 요소 :

내 생산 사용의 경우
package gadams; 

import javax.annotation.PostConstruct; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.annotation.DependsOn; 
import org.springframework.stereotype.Component; 

@Component 
@DependsOn("helloOutFlow") 
public class HelloPublisher { 

    @Autowired 
    private HelloGateway helloGateway; 

    @PostConstruct 
    public void postConstruct() { 
     helloGateway.sendMessage("hello"); 
    } 
} 

우리가 사용하고있는 경우, 우리는 PostConstruct의 방법과 구성 요소가 TaskScheduler는 AMQP 아웃 바운드 어댑터에 의존하는 구성 요소와 그 중 일부 구성 요소를 예약합니다. 즉시 실행. 아웃 바운드 어댑터를 사용하고 게이트웨이 및/또는 게이트웨이 자체를 사용하는 빈에 @DependsOn을 사용하는 IntegrationFlows에 콩 이름을 넣으려고했지만 시작시 오류를 제거하지 않았습니다.

+0

github에서 재생산 테스트 케이스를 여기에 올려 놓았습니다. https://github.com/gadams00/rabbit-race – gadams00

답변

1

모든 것이 Lifecycle입니다. 모든 Spring 통합 엔드 포인트는 start()이 수행 될 때만 메시지를 청취하거나 생성합니다. 그것은 멀리에서 않기 때문에 일반적으로 표준 기본 autoStartup = true 위해이 @PostConstruct (afterPropertiesSet())에서 채널에 메시지를 생산 시작하려면

// Propagate refresh to lifecycle processor first. 
getLifecycleProcessor().onRefresh(); 

ApplicationContext.finishRefresh();에서 이루어집니다

는 매우 일찍 정말 finishRefresh().

생산 논리와 해당 구현을 SmartLifecycle.start() 단계로 재검토해야합니다.

자세한 내용은 Reference Manual을 참조하십시오.

+0

포인터를 주셔서 감사합니다. 이전에는이 ​​매뉴얼의 섹션을 읽지 않았습니다. HelloPublisher를 변경하여 SmartLifecycle을 구현해야하고 게이트웨이 send 호출을 start()에두고 getPhase()에서 Integer.MAX_VALUE를 반환하겠습니까? 그게 문제를 해결하는 것 같아서, 나는 단지 내가 적절하게 이해하고 있는지 확인하고 싶다. – gadams00