私は完全にアノテーション駆動のSpring Boot 1.3.5アプリを持っています。これは別のサービスBeanをオートワイヤリングする必要があるこの非同期サービスを持っています(そして将来はリポジトリをautowireする必要がありますいくつかのビジネス・ロジックを実行するために豆が、私はまだありませんよ):Spring @Asyncは自立豆の使用を許可していません
@Service
public class AsyncService {
@Autowired
public HelpingService helpingService;
@Async
public Future<String> doFoo(String someArgument)
throws InterruptedException {
Thread.sleep(3000);
System.out.println("about to do Foo "+someArgument);
String result = "";
try {
result = helpingService.getSomeStuff(someArgument);
}
catch (Exception e) {
e.printStackTrace();
}
return new AsyncResult<String>(hello);
}
}
上記の方法は、予想通り、他のエンドポイント(非非同期)その仕事を持っている@Controller豆、から呼び出されていることこれを使用しても
@Controller
public class MyController extends BaseController {
@Autowired
HelpingService helpingService;
@Autowired
AsyncService asyncService;
@RequestMapping(method=RequestMethod.GET, value={"/rest/threads/getIp/{jobId}"}, produces={"application/json"})
public ResponseEntity<?> getLog(@PathVariable("jobId") String jobId) throws InterruptedException {
asyncService.doFoo(jobId);
return new ResponseEntity<>(HttpStatus.OK);
}
}
ここにはhelpingService
の実装(それはインターフェイスです)、私は上記の@Asyncメソッドからそれをやっていないよ時に任意のメソッドを呼び出すと、完全に正常に動作します:
@Service
@Validated
public class HelpingServiceImpl implements HelpingService {
@Autowired
HttpSession httpSession;
@Value(value="${projName}")
private String projName;
public String getServerAddress(){
AuthRegion region = (AuthRegion) httpSession.getAttribute("region");
if (region != null)
return region.getServerAddress();
else
return null;
}
@Override
public String getSomeStuff(String jobId) {
String responseString = "";
String projName = this.projName;
String serverAddress = getServerAddress(); // Code stops here with an exception
// Some code here that works fine outside this thread
return responseString;
}
}
これがキャッチされた例外です:
about to do Foo (267)
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:309)
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:366)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:361)
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307)
at com.sun.proxy.$Proxy96.getAttribute(Unknown Source)
at corp.fernandopcg.myapp.service.ThreadServiceImpl.getRundeckServerPort(ThreadServiceImpl.java:45)
at corp.fernandopcg.myapp.service.ThreadServiceImpl.getJobExecutionOutput(ThreadServiceImpl.java:65)
at corp.fernandopcg.myapp.service.AsyncService.doFoo(AsyncService.java:40)
at corp.fernandopcg.myapp.service.AsyncService$$FastClassBySpringCGLIB$$7e164220.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
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)
私は(を同時に延長することができなかったのでいくつかの変更を加えましたが、SpringBootServletInitializer
の例外をキャッチしなければなりませんでした)taskExecutor
私のアプリケーションのメインクラスには、this tutorial私の意見では、私が必要とするものに
@SpringBootApplication
@EnableAsync
@EnableJpaRepositories(repositoryFactoryBeanClass = DataTablesRepositoryFactoryBean.class)
public class MyApplication extends SpringBootServletInitializer implements AsyncConfigurer{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("SomeRandomLookup-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}
}
私の@Async
サービスに、アプリケーションの他のサービスを利用できるように通知することはできますか?それが不可能な場合、私は実際にこれらのスレッド機構の使用を見ることはできません。
さて、HttpSessionをサーブレットスレッドの外側で使用/注入することはできません(これはAsyncを使用して行います)。最も簡単な解決策は、コントローラ内のすべての必要な情報を抽出し、Asyncサービスにデータのみを渡すことです。 –
@MonteCristoええ、これはまさに理由でした。私はスタックトレースを誤解し、 'HttpSession'について本当に考えなかった。 – fernandopcg