在Spring Boot 1.5.4上使用jhipster,我很难让后台任务异步执行;它们似乎使用与我配置的不同的taskExecutor和线程池同步运行。
所有这些都发生在服务中,为了简洁起见,定义如下:
@Service
@Transactional
public class AppService {
@Scheduled(fixedDelay = 3000)
public void consumeData() {
// connect to a subscriber and push data to the workerBee
for(Tuple data : this.getTuples()) {
workerBee(data);
}
}
@Timed
@Async
public void workerBee(Tuple data) throws Exception {
// ... do something that takes 300ms ....
Thread.sleep(300);
}
}
可以说,服务并不是这项工作的理想之地,但出于演示目的,它很适合。
(另外,@Timed无法正常工作,但我在某处看到@Timed在服务内部调用时无法正常工作)
application.yml
的相关部分:
jhipster:
async:
core-pool-size: 8
max-pool-size: 64
queue-capacity: 10000
使用默认的,生成的AsyncConfiguration.java,如下所示:
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("app-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
我已经验证了taskExecutor bean正在创建并正在被liquibase使用。
当我连接visualvm时,我看到pool-2-thread-1
中发生的所有工作,这必须是某种默认情况,并且很明显工作是同步发生的,而不是异步发生的。
我尝试的事情:
@Async("taskExecutor")
答案 0 :(得分:1)
另一种方法是将@Bean
getAsyncExecutor更改为:
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor () {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("app-Executor-");
return executor;
}
答案 1 :(得分:1)
看起来我没有遵循此处列出的规则:http://www.baeldung.com/spring-async。最值得注意的是自我调用:
@Async有两个限制:
it must be applied to public methods only
self-invocation – calling the async method from within the same class – won’t work
答案 2 :(得分:0)
备选方案2:使用CompletableFuture在同一个类中调用异步方法
如果你需要使用异步方法并使用CompletableFuture
在同一个类中调用它并注入Executor
生成的AsyncConfiguration
@Service
public class MyAsyncProcess {
private final Logger log = LoggerFactory.getLogger(MyAsyncProcess.class);
@Autowired
Executor executor;
@Scheduled(cron = "*/8 * * * * *")
public void consumeData() {
IntStream.range(0,20).forEach( (s) ->
CompletableFuture.supplyAsync( () -> { return workerBeeCompletableFuture(String.valueOf(s)); } , executor));
}
public CompletableFuture<String> workerBeeCompletableFuture(String data) {
log.debug("workerBeeCompletableFuture: Iteration number: " + data + " Thread: " + Thread.currentThread().getName());
try { Thread.sleep(2000); }
catch (InterruptedException e) { e.printStackTrace(); }
return CompletableFuture.completedFuture("finished");
}
替代方案1使用@Async
我终于得到导致此行为的原因,实际上@Scheduler
正在调用workerBee
作为本地方法,而不是@Async
方法。
为了让@Async
工作,只需为名为@Service
的{{1}}和@Schedule
MySchedulerService
创建新的@Autowired
AppService
{1}}。同时从MySchedulerService
类中删除@Schedule
。
应该是这样的:
AppService
和计划服务
@Service
public class MyAsyncProcess {
private final Logger log = LoggerFactory.getLogger(MyAsyncProcess.class);
@Async
public void workerBeeAsync(String data) {
// ... do something that takes 300ms ....
try {
log.debug("Iteration number: " + data + " Thread: " + Thread.currentThread().getName());
Thread.sleep(2000);
log.debug("finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在@Service
public class MySchedule {
@Autowired
MyAsyncProcess myAsyncProcess;
@Scheduled(cron = "*/8 * * * * *")
public void consumeData() {
IntStream.range(0,20).forEach(s ->
myAsyncProcess.workerBeeAsync(String.valueOf(s)));
}
}
我使用以下值:
application.yml
jhipster:
async:
core-pool-size: 50
max-pool-size: 100
queue-capacity: 10000
会自动检测@Async
课程中配置的Executor
。
希望对你有所帮助。