Eng*_*_DJ 44 java spring asynchronous
一个@Async在方法@Service-annotated类不被异步调用-它阻塞线程.
我已经进入<task: annotation-driven />了我的配置,并且对该方法的调用来自于类外部,因此代理应该被命中.当我单步执行代码时,代理确实被命中,但它似乎没有任何与任务执行器中运行相关的任何类.
我已经把断点放进去AsyncExecutionInterceptor,他们永远不会受到打击.我调试过AsyncAnnotationBeanPostProcessor,可以看到建议应用.
该服务被定义为一个接口(该方法@Async在那里注释以获得良好的衡量标准),实现的方法也被注释@Async.两者都没有标记@Transactional.
什么想法可能出错了?
- = UPDATE = -
奇怪的是,它只有task在我的app-servlet.xml文件中有我的XML元素时才有效,而不是在我的app-services.xml文件中,如果我也从那里对服务进行组件扫描.通常我有一个只包含控制器的XML文件(并相应地限制组件扫描),另一个包含服务(同样限制了组件扫描,使得它不会重新扫描另一个加载的控制器)文件).
APP-servlet.xml中
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"
>
<task:annotation-driven executor="executor" />
<task:executor id="executor" pool-size="7"/>
<!-- Enable controller annotations -->
<context:component-scan base-package="com.package.store">
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> -->
</context:component-scan>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Run Code Online (Sandbox Code Playgroud)
app-services.xml(在此处指定时不起作用)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<!-- Set up Spring to scan through various packages to find annotated classes -->
<context:component-scan base-package="com.package.store">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<task:annotation-driven executor="han" />
<task:executor id="han" pool-size="6"/>
...
Run Code Online (Sandbox Code Playgroud)
我在配置中遗漏了一些明显的东西,或者配置元素之间是否存在一些微妙的相互作用?
ach*_*ach 28
在Ryan Stewart的这个出色答案的帮助下,我能够解决这个问题(至少对于我的具体问题).
简而言之,ContextLoaderListener(通常来自applicationContext.xml)加载的上下文是DispatcherServlet(通常来自*-servlet.xml)加载的上下文的父级.如果您@Async在两个上下文中都使用声明/组件扫描的方法的bean,则子上下文(DispatcherServlet)中的版本将覆盖父上下文(ContextLoaderListener)中的版本.我通过从组件扫描中排除该组件来验证这一点*-servlet.xml- 它现在按预期工作.
Shi*_*gon 27
对我来说,解决方案是添加@EnableAsync我的@Configuration注释类:
@Configuration
@ComponentScan("bla.package")
@EnableAsync
public class BlaConfiguration {
}
Run Code Online (Sandbox Code Playgroud)
现在bla.package,带有@Async注释方法的包中的类实际上可以异步调用它们.
typ*_*rpr 11
JiříVypědřík的答案解决了我的问题.特别,
- 检查使用@Async注释的方法是否公开.
Spring教程中的另一个有用信息https://spring.io/guides/gs/async-method/:
创建FacebookLookupService类的本地实例不允许findPage方法异步运行.它必须在@Configuration类中创建或由@ComponentScan选取.
这意味着如果你有一个静态方法Foo.bar(),以这种方式调用它将不会在异步中执行它,即使它是用@Async注释的.你必须用@Component注释Foo,并在调用类中得到一个@Autowired的Foo实例.
即,如果你在Foo类中有一个带注释的方法栏:
@Component
class Foo {
@Async
public static void bar(){ /* ... */ }
@Async
public void bar2(){ /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
在您的调用者类中:
class Test {
@Autowired Foo foo;
public test(){
Foo.bar(); // Not async
foo.bar(); // Not async
foo.bar2(); // Async
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:似乎静态调用它也不会在异步中执行它.
希望这可以帮助.
就我而言,该@Async方法与使用该方法的同步方法在同一类中定义,这显然导致所有作业挂在当前线程上。
坏的
@Component
@EnableAsync
public class TranslationGapiReader {
@Async
public CompletableFuture<GapiFile> readFile(String fileId) {
try { Thread.sleep(2000); } catch (Exception exc) { throw new RuntimeException("ololo", exc); }
return CompletableFuture.completedFuture(null);
}
public Stream<GapiFile> readFiles(Iterable<String> fileIds) {
List<CompletableFuture<GapiFile>> futures = new ArrayList<>();
for (String fileId: fileIds) {
futures.add(readFile(fileId));
}
return Stream.empty();
}
}
Run Code Online (Sandbox Code Playgroud)
好的
@Component
@EnableAsync
public class AsyncGapiFileReader {
@Async
public CompletableFuture<TranslationGapiReader.GapiFile> readFile(String fileId) {
try { Thread.sleep(2000); } catch (Exception exc) { throw new RuntimeException("ololo", exc); }
return CompletableFuture.completedFuture(null);
}
}
Run Code Online (Sandbox Code Playgroud)
@Component
@EnableAsync
public class TranslationGapiReader {
@Autowired
AsyncGapiFileReader asyncGapiFileReader;
public Stream<GapiFile> readFiles(Iterable<String> fileIds) {
List<CompletableFuture<GapiFile>> futures = new ArrayList<>();
for (String fileId: fileIds) {
futures.add(asyncGapiFileReader.readFile(fileId));
}
return Stream.empty();
}
}
Run Code Online (Sandbox Code Playgroud)
我不是 Spring 专家,无法理解为什么它只在该@Async方法位于不同类中时才起作用,但这就是我观察到的解决问题的方法。
首先让你的.xml配置看起来像:
<task:scheduler id="myScheduler" pool-size="10" />
<task:executor id="myExecutor" pool-size="10" />
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" proxy-target-class="true" />
Run Code Online (Sandbox Code Playgroud)
(是的,调度器计数和执行器线程池大小是可配置的)
或者只是使用默认值:
<!-- enable task annotation to support @Async, @Scheduled, ... -->
<task:annotation-driven />
Run Code Online (Sandbox Code Playgroud)
其次,确保@Async方法是公开的。
| 归档时间: |
|
| 查看次数: |
69852 次 |
| 最近记录: |