我需要一个POJO方法异步执行,所以我用@Async
注释了它。我已使用正确的@EnableAsync
向@Configuration
课程添加了@ComponentScan
。这是一个小测试案例供您运行。
public class Test {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MyConfig.class);
context.refresh();
Object o = context.getBean(AsyncBean.class);
//((AsyncBean)o).doStuff();
System.out.println(o);
}
@ComponentScan(basePackages = "my.package")
@EnableAsync
@Configuration
// @EnableScheduling
public static class MyConfig {
@Bean
public AsyncBean bean() throws InterruptedException {
AsyncBean b = new AsyncBean();
return b;
}
}
public static class AsyncBean {
//@Scheduled(fixedRate = 10000L, initialDelay = 1000L)
@Async
public void doStuff() throws InterruptedException {
for (int i = 0; i < 5; i++) {
System.out.println("async loop" + i + " -> " + Thread.currentThread().getId());
Thread.sleep(1000L);
}
}
}
}
上面的代码将加载AnnotationConfigApplicationContext
并退出。但是,如果我取消注释//((AsyncBean)o).doStuff();
,那么它将在一个单独的线程中运行。为什么在完全读取配置时,@Async
方法无法启动?这就是我所期望的。
我已经留下了一些@Scheduled
的东西,所以你可以自己尝试一下。在@Scheduled
的情况下,带注释的方法立即被触发(在初始延迟之后)。
我需要为Spring实现一些其他东西才能知道它必须启动我的@Async
方法吗?
答案 0 :(得分:15)
@Async
无意在加载ApplicationContext
后运行。它旨在在调用时以异步方式运行带注释的方法。
如果您希望方法在应用程序启动时运行,那么您应该使用@PostConstruct
注释(在非延迟加载的bean上)。如果您需要该方法以异步方式运行,那么您必须更加棘手,因为同时使用@PostConstruct
和@Async
(as noted in the last paragraph of 25.5.2 here)。
修改强>
@Async
与@Scheduled
之间的差异可能不是documentation中最明显的差异。通常,@Scheduled
用于指示何时应该发生特定方法的下一次调用,并且通常是周期性的。 @Async
用于异步运行方法,也就是说,该方法将在启动后台线程后立即返回以执行方法的工作。
令人困惑的部分是后台线程。他们都使用一个,但他们尝试做的事情的性质是不同的(定期背景工作通常是非用户交互式的,而不是通常由用户发起的一次性背景工作)。