如何发送消息以停止轮询并退出应用程序

时间:2016-10-07 08:48:48

标签: java spring spring-integration

我有弹簧集成应用程序,我需要在处理完所有数据后关闭它。如果我明确地调用appContext.close(),则不能及时处理所有数据(除非我设置Thread.sleep())。如果我没有在应用程序上下文上调用close,那么应用程序不会停止,因为我的后台轮询器不允许应用程序自动关闭。那么如何发信号来停止我的一个服务激活器中的整个应用程序(最后在处理链中)?

  1. 第一个bean逐行从存储中读取数据,并通过while循环中的gateway.send(data)发送
  2. 并行发生的处理链
  3. 比所有线程通过Pollable Queue
  4. 将消息发送到单个线程
  5. 在这里,如果我意识到第一个bean中读取的所有消息都已处理
  6. ,我应该停止应用程序

    我试图使用controlbus停止上一个服务激活器,但它没有帮助

    由于

    更新

    这里有一些代码示例:

    转轮:

    public class Runner {
    static Logger log = LoggerFactory.getLogger(Service2.class);
    
    public static void main(String[] args) throws InterruptedException {
        log.info("START APP");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        RootService service = context.getBean(RootService.class);
        service.start();
        service.stop();
        context.close();
        log.info("END APP");
    }
    

    }

    RootService:

        @Component
    public class RootService {
    
        Logger log = LoggerFactory.getLogger(RootService.class);
    
        @Autowired
        MyGateway gateway;
    
        int totalSize = 0;
    
        public void start() {
            List<String> source = generateSource();
            totalSize = source.size();
            //imitate very long but finite process
            for (String s : source) {
                gateway.send(s, totalSize);
            }
            log.info("end sending data");
        }
    
        public void stop() throws InterruptedException {
            log.info("sending stop signal...");
            while (gateway.sendStop(totalSize)<0) {
                Thread.sleep(100);
                log.info("sending stop signal...");
            }
            log.info("THE END");
        }
    
    
        private List<String> generateSource() {
            List<String> result = new ArrayList<String>();
            for (int i = 0; i < 15; i++) {
                result.add("data" + i);
            }
            return result;
        }
    }
    

    服务1

    @Component
    public class Service1 {
    
        public String dodo(String data) throws InterruptedException {
            //doing a job in parallel
            Thread.sleep(100);
            return data + "-" + Thread.currentThread().getName();
        }
    }
    

    服务2:

        @Component
    public class Service2 {
        Logger log = LoggerFactory.getLogger(Service2.class);
        int counter = 0;
    
        public void dodo(String data) {
            log.info("data: {}-{}", data, Thread.currentThread().getName());
            counter++;
            log.info("counter: {}", counter);
        }
    
        public Integer dodo(Integer data) {
            if (counter < data) {
                return -1;
            } else {
                return 0;
            }
        }
    }
    
    
    @Component
    public class ErrorHandler {
    
        Logger log = LoggerFactory.getLogger(Service2.class);
    
        public void handleError(Message<?> message) {
            log.info("ERROR: {}", message);
        }
    }
    

    和xml config

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/integration"
                 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
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
            http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:task="http://www.springframework.org/schema/task">
    
    
        <gateway id="myGateway"
                 service-interface="com.dimas.MyGateway"
                 default-request-channel="channel1"
                 error-channel="errorChannel"
                 default-reply-timeout="3000">
            <method name="send" request-channel="channel1"/>
            <method name="sendStop" request-channel="channel2" reply-channel="channel3"/>
        </gateway>
    
        <channel id="channel1">
            <dispatcher task-executor="executor"/>
        </channel>
        <channel id="channel2">
            <queue/>
        </channel>
        <channel id="channel3">
            <queue/>
        </channel>
        <channel id="errorChannel"/>
    
        <service-activator input-channel="errorChannel" ref="errorHandler" method="handleError"/>
    
        <service-activator input-channel="channel1" output-channel="channel2" ref="service1"/>
        <service-activator input-channel="channel2" output-channel="channel3" ref="service2">
            <poller fixed-delay="0"/>
        </service-activator>
    
        <task:executor id="executor" pool-size="2"/>
    </beans:beans>
    

    现在它可以正常工作 - 当处理完所有数据并且它返回停止码0时app停止但我在日志中看到很多错误,如:

      

    的ErrorMessage   [有效载荷= org.springframework.messaging.core.DestinationResolutionException:   没有输出通道或replyChannel标头可用,   标题= {ID = 639ca939-8110-4486-6a2b-5d36c7bfdbcd,   时间戳= 1475872251269}]

    错误处理程序成功捕获它但出了点错误

    我意识到问题出在哪里。 Last Service2为任何收入消息返回soemthing。重做它以便它仅响应stopRequest请求的代码。

    只是想知道是否有更简单的解决方案

1 个答案:

答案 0 :(得分:0)

目前尚不清楚为什么,如果您发现自己已完成,则无法关闭应用程序上下文。

您可以使用守护程序线程替换默认的taskScheduler

修改

首先,您不需要所有这些队列通道;简单地将channel1作为执行程序通道将为您提供并发性 - 使用队列通道之后只会增加开销。

在任何情况下,要确定流程何时完成,只需向Service2添加getCounter()方法;然后,在你的main方法中,从上下文中获取service2并等到计数器增加到你期望的数字。

或者,您可以向service2添加倒计时锁存器 - 添加一个方法来设置它......

CountDownLatch latch = new CountDownLatch(source.size());
service2.setCountDownLatch(latch);
for (

...
if (!latch.await(...)) { // add a timeout in case is never completes)
    // failure
}