我有弹簧集成应用程序,我需要在处理完所有数据后关闭它。如果我明确地调用appContext.close()
,则不能及时处理所有数据(除非我设置Thread.sleep()
)。如果我没有在应用程序上下文上调用close,那么应用程序不会停止,因为我的后台轮询器不允许应用程序自动关闭。那么如何发信号来停止我的一个服务激活器中的整个应用程序(最后在处理链中)?
gateway.send(data)
发送我试图使用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请求的代码。
只是想知道是否有更简单的解决方案
答案 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
}