Java Spring异步执行

时间:2017-08-22 15:33:27

标签: spring asynchronous spring-boot jhipster

在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注释中指定执行程序,如@Async("taskExecutor")
  • 使用core-pool-size中的8个线程验证taskExecutor的配置。
  • 验证应用程序是否具有@EnableAsync注释(默认情况下)。

3 个答案:

答案 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

希望对你有所帮助。