Java Spring服务器发送事件-ResponseBodyMitter已设置完成
我正在使用Spring4.3.7.RELEASE来设置服务器发送的事件。并使用Java Spring服务器发送事件-ResponseBodyMitter已设置完成,java,spring,server-sent-events,Java,Spring,Server Sent Events,我正在使用Spring4.3.7.RELEASE来设置服务器发送的事件。并使用@scheduled注释每2秒发送一次消息。 这是控制器 @Controller public class MySSEController { private final SseEmitter sseEmitter = new SseEmitter(); private int counter = 0; @RequestMapping("/ssestream") public SseE
@scheduled
注释每2秒发送一次消息。
这是控制器
@Controller
public class MySSEController {
private final SseEmitter sseEmitter = new SseEmitter();
private int counter = 0;
@RequestMapping("/ssestream")
public SseEmitter getRealTimeMessageAction() throws IOException {
sseEmitter.send("MessageCounter : " + counter);
return sseEmitter;
}
@Scheduled(fixedDelay = 2*1000)
public void scheduledMsgEmitter() throws IOException
{
if(null != sseEmitter) {
sseEmitter.send("MessageCounter : " + ++counter);
}
}
}
我直接从eclipse在Tomcat9上运行这个。应用程序每隔2秒启动并向浏览器发送消息。但一段时间后,它停止发送消息,我在eclipse控制台中看到以下异常
Mar 16, 2017 6:57:34 PM org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver handleAsyncRequestTimeoutException
SEVERE: Async timeout for GET [/streaming-web/stream/ssestream]
Mar 16, 2017 6:57:35 PM org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler handleError
SEVERE: Unexpected error occurred in scheduled task.
java.lang.IllegalStateException: ResponseBodyEmitter is already set complete
at org.springframework.util.Assert.state(Assert.java:70)
at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:158)
at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:126)
at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:107)
at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:89)
at com.mycomp.test.controllers.MySSEController.scheduledMsgEmitter(MySSEController.java:25)
at sun.reflect.GeneratedMethodAccessor31.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
我错过什么了吗?请帮我解决这个问题。我不确定这是否是正确的解决方案。 我已经稍微修改了实现,以便与所有连接的客户端一起工作 此实现不会抛出
非法状态异常
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@Controller
public class MySSEController_Working {
private Set<SseEmitter> sseEmitters = new HashSet<SseEmitter>();
private int messageCount = 0;
@RequestMapping("/ssestream")
public SseEmitter getRealTimeMessageAction(HttpServletRequest request, HttpServletResponse response) throws IOException {
final SseEmitter sseEmitter = new SseEmitter();
sseEmitter.onCompletion(() -> {
synchronized (this.sseEmitters) {
this.sseEmitters.remove(sseEmitter);
}
});
sseEmitter.onTimeout(()-> {
sseEmitter.complete();
});
// Put context in a map
sseEmitters.add(sseEmitter);
return sseEmitter;
}
@Scheduled(fixedDelay = 2*1000)
public void scheduledMsgEmitter() throws IOException
{
if(!sseEmitters.isEmpty())
++messageCount;
else
System.out.println("No active Emitters ");
System.out.println("Sent Messages : " + messageCount);
sseEmitters.forEach(emitter -> {
if (null != emitter)
try {
System.out.println("Timeout : "+ emitter.getTimeout());
emitter.send("MessageCounter : " + messageCount);
emitter.complete();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
import java.io.IOException;
导入java.util.HashSet;
导入java.util.Set;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.springframework.scheduling.annotation.Scheduled;
导入org.springframework.stereotype.Controller;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@控制器
公共类MySSEController\u正在工作{
私有集SSemitters=new HashSet();
private int messageCount=0;
@请求映射(“/ssestream”)
公共SseEmitter getRealTimeMessageAction(HttpServletRequest请求、HttpServletResponse响应)引发IOException{
最终SseEmitter SseEmitter=新SseEmitter();
SSEEmiter.onCompletion(()->{
已同步(此.sseEmitters){
此.sseEmitters.remove(sseEmitter);
}
});
sseEmitter.onTimeout(()->{
完成();
});
//在地图中放置上下文
添加(sseEmitter);
返回发射器;
}
@计划(固定延迟=2*1000)
public void scheduledMgitter()引发IOException
{
如果(!sseEmitters.isEmpty())
++消息计数;
其他的
System.out.println(“无有源发射器”);
System.out.println(“发送的消息:+messageCount”);
SSEEmiters.forEach(发射器->{
if(null!=发射器)
试一试{
System.out.println(“超时:+emitter.getTimeout());
发送(“MessageCounter:+messageCount”);
emitter.complete();
}捕获(IOE异常){
e、 printStackTrace();
}
});
}
}
以毫秒为单位:60001是60秒。这是一个会话超时,不受会话活动的影响
需要将超时设置为会话的预期持续时间(以毫秒为单位)。因此,86400000(或更多)是完全合适的。您是否尝试过使用自定义超时选项的SSEEmiter构造函数?@gvmani是的,我尝试过。我使用
新的SSE发射器(60000l)
尝试,并在1分钟后遇到相同的异常。在浏览器中收到的最后一条消息是“MessageCounter:31”嗨@Pete,您是否找到了此问题的解决方案。请发布解决方案,我也面临同样的问题,谢谢,@Mohammadnabil请看下面我的答案。我在事件发射器的实现中做了一些修改。