Spring and threads: TaskExecutor

When you want to run long tasks in a web application, don't forget to use Spring's TaskExecutor, which helps you manage related components.

It's not uncommon to use threads in web applications, especially if you need to develop long-running tasks.

In Spring, we must pay special attention and use the tools it already provides, rather than using our own way of creating new threads.

We want our threads to be managed by Spring so that other components of the application can be used without any ill effects. We also want to shut down the application gracefully, rather than closing with some work unfinished.

Spring provides TaskExecutorabstractions as task executors.

Spring's TaskExecutorinterface is the java.util.concurrent.Executorsame as an interface.
A number of pre-built implementations are included in the Spring distribution TaskExecutor, and you can find out more about them from the official documentation .

By providing an TaskExecutorimplementation for the Spring environment, you will be able to TaskExecutorinject beans into other beans and have access to managed threads:

package com.gkatzioura.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Service
public class AsynchronousService {

    @Autowired
    private ApplicationContext applicationContext;

    // 注入一个TaskExecutor实现
    @Autowired
    private TaskExecutor taskExecutor;

    // 该方法是同步的,但是其调用taskExecutor.execute()中的run()会在另外一个
    // 线程中异步执行
    public void executeAsynchronously() {
        taskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                // 这里是需要异步执行的长时间任务逻辑
            }
        });
    }
}

To use it as above TaskExecutor, the first step is to add the TaskExecutorconfiguration to our Spring application:

package com.gkatzioura.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Configuration
public class ThreadConfig {
    // 定义一个类型为TaskExecutor的bean,方法名字无所谓
    @Bean
    public TaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setThreadNamePrefix("default_task_executor_thread");
        executor.initialize();
        return executor;
    }
}

Once we configure the executor (annotation: that is, the TaskExecutorbean configured above), the task processing is very simple. We inject the actuator TaskExecutorbean into another Spring component and submit the Runnableobject containing the task to be executed.

Because asynchronous code may need to interact with other components of the application, the best approach is to create prototype prototype-scoped ( ) Runnablebean instances and then inject them. Examples are as follows:

package com.gkatzioura;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
 * Created by gkatzioura on 10/18/17.
 */
@Component
@Scope("prototype")
public class MyThread implements Runnable {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyThread.class);
    @Override
    public void run() {
        LOGGER.info("Called from thread");
    }
}

We can then inject an executor (of type TaskExecutorexecutor above) into our service and use it to execute Runnableinstances.


package com.gkatzioura.service;
import com.gkatzioura.MyThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * Created by gkatzioura on 4/26/17.
 */
@Service
public class AsynchronousService {
    @Autowired
    private TaskExecutor taskExecutor;
    @Autowired
    private ApplicationContext applicationContext;
    public void executeAsynchronously() {
        // 获取我们自定义的作用域为prototype的可执行任务Runnable bean
        MyThread myThread = applicationContext.getBean(MyThread.class);
        // 使用 taskExecutor对其进行异步执行
        taskExecutor.execute(myThread);
    }
}

In the next article , we'll take our multithreaded codebase to the next level by using Spring's asynchronous functions.

You can find the source code mentioned in this article on GitHub .

English original

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325641348&siteId=291194637