All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.scheduling.concurrent;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.UsesJava7;
import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable;
import org.springframework.scheduling.support.TaskUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;

/**
 * {@link org.springframework.beans.factory.FactoryBean} that sets up
 * a {@link java.util.concurrent.ScheduledExecutorService}
 * (by default: a {@link java.util.concurrent.ScheduledThreadPoolExecutor})
 * and exposes it for bean references.
 *
 * 

Allows for registration of {@link ScheduledExecutorTask ScheduledExecutorTasks}, * automatically starting the {@link ScheduledExecutorService} on initialization and * cancelling it on destruction of the context. In scenarios that only require static * registration of tasks at startup, there is no need to access the * {@link ScheduledExecutorService} instance itself in application code at all; * ScheduledExecutorFactoryBean is then just being used for lifecycle integration. * *

Note that {@link java.util.concurrent.ScheduledExecutorService} * uses a {@link Runnable} instance that is shared between repeated executions, * in contrast to Quartz which instantiates a new Job for each execution. * *

WARNING: {@link Runnable Runnables} submitted via a native * {@link java.util.concurrent.ScheduledExecutorService} are removed from * the execution schedule once they throw an exception. If you would prefer * to continue execution after such an exception, switch this FactoryBean's * {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"} * property to "true". * * @author Juergen Hoeller * @since 2.0 * @see #setPoolSize * @see #setRemoveOnCancelPolicy * @see #setThreadFactory * @see ScheduledExecutorTask * @see java.util.concurrent.ScheduledExecutorService * @see java.util.concurrent.ScheduledThreadPoolExecutor */ @SuppressWarnings("serial") public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport implements FactoryBean { // ScheduledThreadPoolExecutor.setRemoveOnCancelPolicy(boolean) only available on JDK 7+ private static final boolean setRemoveOnCancelPolicyAvailable = ClassUtils.hasMethod(ScheduledThreadPoolExecutor.class, "setRemoveOnCancelPolicy", boolean.class); private int poolSize = 1; private ScheduledExecutorTask[] scheduledExecutorTasks; private boolean removeOnCancelPolicy = false; private boolean continueScheduledExecutionAfterException = false; private boolean exposeUnconfigurableExecutor = false; private ScheduledExecutorService exposedExecutor; /** * Set the ScheduledExecutorService's pool size. * Default is 1. */ public void setPoolSize(int poolSize) { Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher"); this.poolSize = poolSize; } /** * Register a list of ScheduledExecutorTask objects with the ScheduledExecutorService * that this FactoryBean creates. Depending on each ScheduledExecutorTask's settings, * it will be registered via one of ScheduledExecutorService's schedule methods. * @see java.util.concurrent.ScheduledExecutorService#schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit) * @see java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit) * @see java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit) */ public void setScheduledExecutorTasks(ScheduledExecutorTask... scheduledExecutorTasks) { this.scheduledExecutorTasks = scheduledExecutorTasks; } /** * Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor} (JDK 7+). *

Default is {@code false}. If set to {@code true}, the target executor will be * switched into remove-on-cancel mode (if possible, with a soft fallback otherwise). */ public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) { this.removeOnCancelPolicy = removeOnCancelPolicy; } /** * Specify whether to continue the execution of a scheduled task * after it threw an exception. *

Default is "false", matching the native behavior of a * {@link java.util.concurrent.ScheduledExecutorService}. * Switch this flag to "true" for exception-proof execution of each task, * continuing scheduled execution as in the case of successful execution. * @see java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate */ public void setContinueScheduledExecutionAfterException(boolean continueScheduledExecutionAfterException) { this.continueScheduledExecutionAfterException = continueScheduledExecutionAfterException; } /** * Specify whether this FactoryBean should expose an unconfigurable * decorator for the created executor. *

Default is "false", exposing the raw executor as bean reference. * Switch this flag to "true" to strictly prevent clients from * modifying the executor's configuration. * @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService */ public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) { this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor; } @Override @UsesJava7 protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { ScheduledExecutorService executor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler); if (this.removeOnCancelPolicy) { if (setRemoveOnCancelPolicyAvailable && executor instanceof ScheduledThreadPoolExecutor) { ((ScheduledThreadPoolExecutor) executor).setRemoveOnCancelPolicy(true); } else { logger.info("Could not apply remove-on-cancel policy - not a Java 7+ ScheduledThreadPoolExecutor"); } } // Register specified ScheduledExecutorTasks, if necessary. if (!ObjectUtils.isEmpty(this.scheduledExecutorTasks)) { registerTasks(this.scheduledExecutorTasks, executor); } // Wrap executor with an unconfigurable decorator. this.exposedExecutor = (this.exposeUnconfigurableExecutor ? Executors.unconfigurableScheduledExecutorService(executor) : executor); return executor; } /** * Create a new {@link ScheduledExecutorService} instance. *

The default implementation creates a {@link ScheduledThreadPoolExecutor}. * Can be overridden in subclasses to provide custom {@link ScheduledExecutorService} instances. * @param poolSize the specified pool size * @param threadFactory the ThreadFactory to use * @param rejectedExecutionHandler the RejectedExecutionHandler to use * @return a new ScheduledExecutorService instance * @see #afterPropertiesSet() * @see java.util.concurrent.ScheduledThreadPoolExecutor */ protected ScheduledExecutorService createExecutor( int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler); } /** * Register the specified {@link ScheduledExecutorTask ScheduledExecutorTasks} * on the given {@link ScheduledExecutorService}. * @param tasks the specified ScheduledExecutorTasks (never empty) * @param executor the ScheduledExecutorService to register the tasks on. */ protected void registerTasks(ScheduledExecutorTask[] tasks, ScheduledExecutorService executor) { for (ScheduledExecutorTask task : tasks) { Runnable runnable = getRunnableToSchedule(task); if (task.isOneTimeTask()) { executor.schedule(runnable, task.getDelay(), task.getTimeUnit()); } else { if (task.isFixedRate()) { executor.scheduleAtFixedRate(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit()); } else { executor.scheduleWithFixedDelay(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit()); } } } } /** * Determine the actual Runnable to schedule for the given task. *

Wraps the task's Runnable in a * {@link org.springframework.scheduling.support.DelegatingErrorHandlingRunnable} * that will catch and log the Exception. If necessary, it will suppress the * Exception according to the * {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"} * flag. * @param task the ScheduledExecutorTask to schedule * @return the actual Runnable to schedule (may be a decorator) */ protected Runnable getRunnableToSchedule(ScheduledExecutorTask task) { return (this.continueScheduledExecutionAfterException ? new DelegatingErrorHandlingRunnable(task.getRunnable(), TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER) : new DelegatingErrorHandlingRunnable(task.getRunnable(), TaskUtils.LOG_AND_PROPAGATE_ERROR_HANDLER)); } @Override public ScheduledExecutorService getObject() { return this.exposedExecutor; } @Override public Class getObjectType() { return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ScheduledExecutorService.class); } @Override public boolean isSingleton() { return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy