rd2*_*d22 7 java spring asynchronous spring-mvc
我有一个彗星(长轮询)Controller
呼叫,这需要在一些id和puts
然后进入阻塞队列,如果没有计算该id运行时,用于Consumer
向take
从queue
与这些ID执行计算.我正在使用Springs
DeferredResult
asynch支持.
我维持Map
的DeferredResult
,并在请求中接收到的相应的ID.当在消费者线程中完成id的计算时,我在其中检查该id Map
并设置关联DeferredResults
setResult
,该响应将响应发送回客户端.
在Controller
方法中,我有一个onCompletion
回调,DeferredResult
从中删除此DeferredResult
对象Map
.
然后,客户端从其请求中删除此ID并发送剩余的ID.例如,客户端发送的初始ID为"1,2,3",它们都被插入BlockingQueue
并且说id"2"的计算先前完成,然后DeferredResults
setResult
将其设置,这将响应返回给客户端.通过回调,这DeferredResult
将被删除Map
.并且下一个请求中的客户端将发送ID"1,3".
现在一切正常,但是当我开始为此编写测试用例时,onCompletion
永远不会调用回调.我甚至在泉水官方的例子中试过它,它似乎甚至没有被称为.有没有办法在我的实现中调用它,或者某些东西是不正确的.
这是我的Controller
方法:
@RequestMapping(value = "views/getLongPollingGraphData", method = RequestMethod.GET, headers = "Accept=application/json")
@ResponseBody
public DeferredResult<WebServiceResponse> getLongGraphData(
HttpServletRequest request,
@RequestParam(value = "ids") String ids)
{
//create a default response in case, when no result has been calculated till timeout
WebServiceResponse awrDefault = new WebServiceResponse();
//set time out this DeferredResult, after 5 seconds
final DeferredResult<WebServiceResponse> deferredResult = new DeferredResult<WebServiceResponse>(5000L, awrDefault);
//logic to set in blocking queue
//mMapOfDeferredResultAndViews.put(deferredResult, listOfViews.keySet());
deferredResult.onCompletion(new Runnable() {
@Override
public void run()
{
mMapOfDeferredResultAndViews.remove(deferredResult);
}
});
return deferredResult;
}
Run Code Online (Sandbox Code Playgroud)
以下是测试用例的一部分:
@Before
public void setup()
{
this.mockMvc = webAppContextSetup(this.wac).build();
}
@Test
public void testLongPollGraphData()
{
try
{
String ids = "22,23,25";
List<Integer> idList = convertStringToList(ids);
while(idList.size() > 0)
{
MvcResult mvcResult = this.mockMvc.perform(get("/views/getLongPollingGraphData")
.contentType(MediaType.APPLICATION_JSON)
.param("ids", ids)
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult));
WebServiceResponse result = (WebServiceResponse)mvcResult.getAsyncResult();
if(result != null)
{
EJSChartsData chartsData = (EJSChartsData)result.getResponse();
if(chartsData != null && chartsData.getViewId() != -1)
{
int viewId = chartsData.getViewId();
idList.remove((Integer)viewId);
ids = idList.toString().replace("[", "").replace("]", "");
}
}
}
}
catch(Exception e)
{
fail(e.toString());
}
}
Run Code Online (Sandbox Code Playgroud)
该Controller
方法被调用,我按预期收到响应,但由于onCompletion
回调从未被调用,我通过删除id再次调用方法的逻辑将命中作为Map
过去的保持DeferredResult
.
更新
测试类注释是:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
@WebAppConfiguration
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
Run Code Online (Sandbox Code Playgroud)
我还有一个观察,呼叫getLongPollingGraphData
没有完成,也就是说,它不会等待5秒指定的超时时间,并立即返回并导致result
要null
.我读了它,建议添加.andExpect(request().asyncResult("Expected output"))
到mockMvc
对象.
但这是我的测试用例的全部内容,我希望计算并返回结果,以便我可以根据收到的响应重新发送修改我的ids变量的请求.
你使用什么版本的Spring?我已经针对类似情况打开了SPR-13615,并在 4.2.3 中修复了该问题(影响 4.2.2)。
如果您查看评论,您可以使用以下方法解决此问题而无需更新
mvcResult.getRequest().getAsyncContext().complete();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
985 次 |
最近记录: |