Shutdown @Bean ExecutorService using @PreDestroy

2.4k Views Asked by At

I have a Spring @Configuration class as follows:

@Configuration
public class ExecutorServiceConfiguration {

    @Bean
    public BlockingQueue<Runnable> queue() {
        return ArrayBlockingQueue<>(1000);
    }     

    @Bean
    public ExecutorService executor(BlockingQueue<Runnable> queue) {
        return ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue);
    }

    @PreDestroy
    public void shutdownExecutor() {
        // no executor instance
    }
}

I would also like to specify a @PreDestroy method which shuts down the ExecutorService. However, the @PreDestroy method cannot have any arguments which is why I'm not able to pass the executor bean to this method in order to shut it. Specifying destroy method in @Bean(destroyMethod = "...") does not work either. It allows me to specify existing shutdown or shutdownNow, but not the custom method which I intend to use.

I know I could instantiate the queue and executor directly and not as Spring beans, but I'd rather do it this way.

2

There are 2 best solutions below

0
On BEST ANSWER

I love defining classes inline:

@Bean(destroyMethod = "myCustomShutdown")
public ExecutorService executor(BlockingQueue<Runnable> queue) {
    return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue) {
        public void myCustomShutdown() {
            ...
        }
    };
}
1
On

Use the ThreadPoolTaskExecutor which does all that by default.

@Configuration
public class ExecutorServiceConfiguration {

    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor() {
            protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
                return new ArrayBlockingQueue<>(queueCapacity);
            }
        };
        taskExecutor.setCorePoolSize(1);
        taskExecutor.setMaxPoolSize(1);
        taskExecutor.setKeepAliveSeconds(0);
        taskExecutor.setQueueCapacity(1000);
        return taskExecutor;
    }    
}

This will configure the ThreadPoolExecutor and shutdown when the application stops.

If you don't need the ArrayBlockingQueue but can live with the default LinkedBlockingQueue and only need to specify the queue capacity you can remove the override createQueue method.