rd2*_*d22 7 java spring asynchronous spring-mvc
我有一个彗星(长轮询)Controller呼叫,这需要在一些id和puts然后进入阻塞队列,如果没有计算该id运行时,用于Consumer向take从queue与这些ID执行计算.我正在使用Springs DeferredResultasynch支持.
我维持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 次 |
| 最近记录: |