Статьи

Spring и Threads: TaskExecutor

Использование потоков в веб-приложении не является чем-то необычным, особенно если вам приходится разрабатывать длительные задачи.

Учитывая весну, мы должны уделять больше внимания и использовать инструменты, которые она уже предоставляет, вместо того, чтобы создавать свои собственные темы. Мы хотим, чтобы пружины управлялись нашими потоками и, таким образом, могли использовать другие компоненты нашего приложения без каких-либо последствий, а также корректно завершать работу нашего приложения без какой-либо работы.

Spring предоставляет TaskExecutor в качестве абстракции для работы с исполнителями. Интерфейс TaskExecutor в Spring идентичен интерфейсу java.util.concurrent.Executor. Существует несколько встроенных реализаций TaskExecutor, включенных в дистрибутив Spring, о которых вы можете узнать в официальной документации . Предоставляя вашей весенней среде реализацию TaskExecutor, вы сможете внедрить TaskExecutor в ваши компоненты и иметь доступ к управляемым потокам.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
 
    @Autowired
    private TaskExecutor taskExecutor;
 
    public void executeAsynchronously() {
 
        taskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                //TODO add long running task
            }
        });
    }
}

Первый шаг — добавить конфигурацию TaskExecutor в наше весеннее приложение.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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 {
 
    @Bean
    public TaskExecutor threadPoolTaskExecutor() {
 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(4);
        executor.setThreadNamePrefix("default_task_executor_thread");
        executor.initialize();
 
        return executor;
    }
 
}

После того, как мы настроим нашего исполнителя, процесс будет простым. Мы внедряем исполнителя в компонент Spring, а затем отправляем классы Runnable, содержащие задачи, которые должны быть выполнены.

Поскольку нашему асинхронному коду также может понадобиться взаимодействовать с другими компонентами нашего приложения и внедрять их, хорошим подходом является создание прототипа запускаемых экземпляров с областью действия.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
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");
    }
}

Затем мы готовы внедрить исполнителя в наши сервисы и использовать его для выполнения запускаемых экземпляров.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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() {
 
        MyThread myThread = applicationContext.getBean(MyThread.class);
        taskExecutor.execute(myThread);
    }
 
}

В следующей статье мы выведем нашу многопоточную кодовую базу на новый уровень, используя асинхронные функции Spring.

Вы можете найти исходный код на github .

Опубликовано на Java Code Geeks с разрешения Эммануила Гкациоураса, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Spring и Threads: TaskExecutor

Мнения, высказанные участниками Java Code Geeks, являются их собственными.