Spring MVC 中的 TaskExecutor 不是异步的
TaskExecutor in Spring MVC is not asynchronous
工作管理器在管理控制台中定义,池大小最小为 1 和 5。该 Web 应用具有以下配置。
Web.xml
<web-app id="RestController" metadata-complete="true" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>rest-controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest-controller</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
申请-Context.xml
`<!-- Empty. I moved all the servlet related entities from here -->`
rest-Controller-servlet.xml
<context:component-scan base-package="com.package.main-pack" />
<task:annotation-driven executor="taskExecutor"/>
<mvc:annotation-driven />
<task:executor id="taskExecutor" pool-size="5" />
RestController.java
@RequestMapping(value = "/reportFake", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public List<String> searchFake() {
List<String> stringArr = new ArrayList<String>();
for (String folder : foldername) {
Future<String> result = reportLookup.doParallelFake(folder);
try {
while (true) {
if (result.isDone()) {
stringArr.add(result.get());
Logger.debug(RestController.class,
"Executed and Returned");
break;
}
}
} catch (InterruptedException e) {
Logger.error(RestController.class, e.getMessage());
} catch (ExecutionException e) {
Logger.error(RestController.class, e.getMessage());
}
}
return stringArr;
}
ReportLookupExecutor.java
@Service("reportLookup")
public class ReportLookupExecutor implements ReportLookupIntf {
@Async("taskExecutor")
@Async("taskExecutor")
@Override
public Future<String> doParallelFake(String folder) {
logger.debug("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("Folder Name :: " + folder);
} catch (InterruptedException e) {
logger.error(e);
}
return null;
}
输出
[11/4/15 12:41:24:349 EST] 0000014d SystemOut O [DEBUG] 04 Nov 12:41:24 PM taskExecutor-1 Execute method asynchronously - taskExecutor-1
[11/4/15 12:41:29:365 EST] 0000007b SystemOut O [DEBUG] 04 Nov 12:41:29 PM WebContainer : 3 Executed and Returned
[11/4/15 12:41:29:366 EST] 0000014e SystemOut O [DEBUG] 04 Nov 12:41:29 PM taskExecutor-2 Execute method asynchronously - taskExecutor-2
[11/4/15 12:41:34:365 EST] 0000007b SystemOut O [DEBUG] 04 Nov 12:41:34 PM WebContainer : 3 Executed and Returned
现在,我尝试关注this link。
我手动抛出一个异常来检查堆栈跟踪,发现它被 ibm.asynchbeans 运行 并被 Spring 适当拦截。这是堆栈跟踪中的一个片段。
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.call(AsyncExecutionInterceptor.java:97)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:314)
at java.util.concurrent.FutureTask.run(FutureTask.java:149)
at org.springframework.scheduling.commonj.DelegatingWork.run(DelegatingWork.java:61)
at com.ibm.ws.asynchbeans.J2EEContext.run(J2EEContext.java:1178)
at com.ibm.ws.asynchbeans.WorkWithExecutionContextImpl.go(WorkWithExecutionContextImpl.java:199)
at com.ibm.ws.asynchbeans.CJWorkItemImpl.run(CJWorkItemImpl.java:236)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862)
非常感谢任何帮助。
好的!我终于能够做到 运行。解决方案是在获取 future 的第一个值之前对 async 方法进行所有调用。我能够通过创建一个未来对象列表来做到这一点。这就是最终调用 class 的样子。
RestController.java
@RequestMapping(value = "/reportFake", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public List<String> searchFake() throws InterruptedException,
ExecutionException {
List<Future<String>> futureArr = new ArrayList<Future<String>>();
for (String folder : new String[] { "One", "Two", "Three", "Four" }) {
futureArr.add(reportLookup.doParallelFake(folder));
}
List<String> stringArr = new ArrayList<String>();
for (Future<String> future : futureArr) {
stringArr.add(future.get());
}
return stringArr;
}
工作管理器在管理控制台中定义,池大小最小为 1 和 5。该 Web 应用具有以下配置。
Web.xml
<web-app id="RestController" metadata-complete="true" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>rest-controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest-controller</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
申请-Context.xml
`<!-- Empty. I moved all the servlet related entities from here -->`
rest-Controller-servlet.xml
<context:component-scan base-package="com.package.main-pack" />
<task:annotation-driven executor="taskExecutor"/>
<mvc:annotation-driven />
<task:executor id="taskExecutor" pool-size="5" />
RestController.java
@RequestMapping(value = "/reportFake", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public List<String> searchFake() {
List<String> stringArr = new ArrayList<String>();
for (String folder : foldername) {
Future<String> result = reportLookup.doParallelFake(folder);
try {
while (true) {
if (result.isDone()) {
stringArr.add(result.get());
Logger.debug(RestController.class,
"Executed and Returned");
break;
}
}
} catch (InterruptedException e) {
Logger.error(RestController.class, e.getMessage());
} catch (ExecutionException e) {
Logger.error(RestController.class, e.getMessage());
}
}
return stringArr;
}
ReportLookupExecutor.java
@Service("reportLookup")
public class ReportLookupExecutor implements ReportLookupIntf {
@Async("taskExecutor")
@Async("taskExecutor")
@Override
public Future<String> doParallelFake(String folder) {
logger.debug("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("Folder Name :: " + folder);
} catch (InterruptedException e) {
logger.error(e);
}
return null;
}
输出
[11/4/15 12:41:24:349 EST] 0000014d SystemOut O [DEBUG] 04 Nov 12:41:24 PM taskExecutor-1 Execute method asynchronously - taskExecutor-1
[11/4/15 12:41:29:365 EST] 0000007b SystemOut O [DEBUG] 04 Nov 12:41:29 PM WebContainer : 3 Executed and Returned
[11/4/15 12:41:29:366 EST] 0000014e SystemOut O [DEBUG] 04 Nov 12:41:29 PM taskExecutor-2 Execute method asynchronously - taskExecutor-2
[11/4/15 12:41:34:365 EST] 0000007b SystemOut O [DEBUG] 04 Nov 12:41:34 PM WebContainer : 3 Executed and Returned
现在,我尝试关注this link。 我手动抛出一个异常来检查堆栈跟踪,发现它被 ibm.asynchbeans 运行 并被 Spring 适当拦截。这是堆栈跟踪中的一个片段。
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.call(AsyncExecutionInterceptor.java:97)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:314)
at java.util.concurrent.FutureTask.run(FutureTask.java:149)
at org.springframework.scheduling.commonj.DelegatingWork.run(DelegatingWork.java:61)
at com.ibm.ws.asynchbeans.J2EEContext.run(J2EEContext.java:1178)
at com.ibm.ws.asynchbeans.WorkWithExecutionContextImpl.go(WorkWithExecutionContextImpl.java:199)
at com.ibm.ws.asynchbeans.CJWorkItemImpl.run(CJWorkItemImpl.java:236)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862)
非常感谢任何帮助。
好的!我终于能够做到 运行。解决方案是在获取 future 的第一个值之前对 async 方法进行所有调用。我能够通过创建一个未来对象列表来做到这一点。这就是最终调用 class 的样子。
RestController.java
@RequestMapping(value = "/reportFake", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public List<String> searchFake() throws InterruptedException,
ExecutionException {
List<Future<String>> futureArr = new ArrayList<Future<String>>();
for (String folder : new String[] { "One", "Two", "Three", "Four" }) {
futureArr.add(reportLookup.doParallelFake(folder));
}
List<String> stringArr = new ArrayList<String>();
for (Future<String> future : futureArr) {
stringArr.add(future.get());
}
return stringArr;
}