繁体   English   中英

如何在Spring-Boot中启动(并最终停止)守护程序线程?

[英]How to start (and eventually stop) a daemon thread in Spring-Boot?

我正在编写一个Spring-Boot应用程序来监视目录并处理正在添加到它的文件。 我通过在Application类中创建一个ApplicationRunner来启动一个线程,该类调用一个用@Async注释的方法:

@SpringBootApplication
@EnableAsync
public class Application {

    @Autowired
    private DirectoryMonitorService directoryMonitorService;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public ApplicationRunner startDirectoryMonitorService() {
        return args -> directoryMonitorService.monitorSourceDirectoty();
    }
}

以下是DirectoryMonitorService的代码,该代码具有使用@Async注释的方法:

@Service
public class DirectoryMonitorService {

    private static final Logger logger = LogManager.getLogger(DirectoryMonitorService.class);

    @Value("${timeout}")
    private long timeout;

    @Autowired
    private WatchService watchService;

    @Async
    public void monitorSourceDirectoty() {
        while (true) {
            WatchKey watchKey;
            try {
                watchKey = watchService.poll(timeout, TimeUnit.SECONDS);
            } catch (ClosedWatchServiceException | InterruptedException e) {
                logger.error("Exception occured while polling from source file", e);
                return;
            }

            // process the WatchEvents

            if (!watchKey.reset()) {
                break;
            }
        }
    }
}

最后,我在这里创建ThreadPoolTask​​Executor

public class AsyncConfig extends AsyncConfigurerSupport {

    private static final Logger logger = LogManager.getLogger(AsyncConfig.class);

    private static final String THREAD_NAME_PREFIX = "Parser-";

    @Value("${corePoolSize}")
    public int corePoolSize;

    @Value("${maxPoolSize}")
    public int maxPoolSize;

    @Value("${queueCapacity}")
    public int queueCapacity;

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (Throwable ex, Method method, Object... params) -> {
            logger.error("Exception message - " + ex.getMessage());
            logger.error("Method name - " + method.getName());
            for (Object param : params) {
                logger.error("Parameter value - " + param);
            }
        };
    }
}

不知怎的,我觉得这不是启动主线程最优雅的方式。 有人有更好的解决方案吗?

另外我宁愿使用Boolean变量替换while (true) ,当Spring-Boot关闭时,我可以将其设置为false。 有谁知道我需要为此实现哪个接口?

如果您想要一个非常简单的实现并且不再可靠,那么这是正确的。

@Async用于较短的任务,并且在重启等方面的能力非常有限。

而且, @Async将在每次监视序列激活时继续创建单独的线程,并且它将使线程池淹没并开始抛出异常,这是非常明显的,如果你有长时间运行的任务,

//处理WatchEvents

除此之外你的实施是正确的(在我看来)。

一些建议(如果你想让事情变得有趣/复杂):

因此,您可以使用某种持久性机制显示跟踪文件,并触发解耦批处理(可以使用Spring Batch )来处理执行,并将这些批处理放入单独的UI或其他内容中,您可以拥有这些批处理中的每一个在UI上停止,启动,恢复。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM