Simplified the task scheduler configuration and exposed setters/constructors for ScheduledExecutorService (INT-113).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.adapter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
@@ -97,9 +98,7 @@ public class PollingSourceAdapter<T> extends AbstractSourceAdapter<T> implements
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("no task scheduler has been provided, will create one");
|
||||
}
|
||||
SimpleMessagingTaskScheduler taskScheduler = new SimpleMessagingTaskScheduler();
|
||||
taskScheduler.setCorePoolSize(1);
|
||||
this.scheduler = taskScheduler;
|
||||
this.scheduler = new SimpleMessagingTaskScheduler(Executors.newSingleThreadScheduledExecutor());
|
||||
}
|
||||
if (!this.scheduler.isRunning()) {
|
||||
this.scheduler.start();
|
||||
|
||||
@@ -20,6 +20,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -47,7 +49,6 @@ import org.springframework.integration.scheduling.MessagingTaskSchedulerAware;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.integration.scheduling.SimpleMessagingTaskScheduler;
|
||||
import org.springframework.integration.scheduling.Subscription;
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -58,21 +59,24 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lifecycle {
|
||||
|
||||
private Log logger = LogFactory.getLog(this.getClass());
|
||||
private static final int DEFAULT_DISPATCHER_POOL_SIZE = 10;
|
||||
|
||||
private ChannelRegistry channelRegistry = new DefaultChannelRegistry();
|
||||
|
||||
private Map<String, MessageEndpoint> endpoints = new ConcurrentHashMap<String, MessageEndpoint>();
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private Map<MessageChannel, SchedulingMessageDispatcher> dispatchers = new ConcurrentHashMap<MessageChannel, SchedulingMessageDispatcher>();
|
||||
private final ChannelRegistry channelRegistry = new DefaultChannelRegistry();
|
||||
|
||||
private List<Lifecycle> lifecycleSourceAdapters = new CopyOnWriteArrayList<Lifecycle>();
|
||||
private final Map<String, MessageEndpoint> endpoints = new ConcurrentHashMap<String, MessageEndpoint>();
|
||||
|
||||
private MessagingTaskScheduler taskScheduler;
|
||||
private final Map<MessageChannel, SchedulingMessageDispatcher> dispatchers = new ConcurrentHashMap<MessageChannel, SchedulingMessageDispatcher>();
|
||||
|
||||
private int dispatcherPoolSize = 10;
|
||||
private final List<Lifecycle> lifecycleSourceAdapters = new CopyOnWriteArrayList<Lifecycle>();
|
||||
|
||||
private boolean autoCreateChannels;
|
||||
private volatile MessagingTaskScheduler taskScheduler;
|
||||
|
||||
private volatile ScheduledExecutorService executor;
|
||||
|
||||
private volatile boolean autoCreateChannels;
|
||||
|
||||
private volatile boolean autoStartup = true;
|
||||
|
||||
@@ -82,7 +86,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
|
||||
|
||||
private volatile boolean running;
|
||||
|
||||
private Object lifecycleMonitor = new Object();
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
@@ -99,23 +103,11 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
|
||||
}
|
||||
}
|
||||
|
||||
public void setMessagingTaskScheduler(MessagingTaskScheduler taskScheduler) {
|
||||
Assert.notNull(taskScheduler, "task scheduler must not be null");
|
||||
if (taskScheduler instanceof SimpleMessagingTaskScheduler) {
|
||||
((SimpleMessagingTaskScheduler) taskScheduler).setCorePoolSize(dispatcherPoolSize);
|
||||
}
|
||||
this.taskScheduler = taskScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size for the dispatcher thread pool.
|
||||
* Set the {@link ScheduledExecutorService} to use for scheduling message dispatchers.
|
||||
*/
|
||||
public void setDispatcherPoolSize(int dispatcherPoolSize) {
|
||||
Assert.isTrue(dispatcherPoolSize > 0, "'dispatcherPoolSize' must be at least 1");
|
||||
this.dispatcherPoolSize = dispatcherPoolSize;
|
||||
if (this.taskScheduler != null && this.taskScheduler instanceof SimpleMessagingTaskScheduler) {
|
||||
((SimpleMessagingTaskScheduler) this.taskScheduler).setCorePoolSize(dispatcherPoolSize);
|
||||
}
|
||||
public void setScheduledExecutorService(ScheduledExecutorService executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,25 +162,16 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
|
||||
if (this.getErrorChannel() == null) {
|
||||
this.setErrorChannel(new SimpleChannel(Integer.MAX_VALUE));
|
||||
}
|
||||
if (this.taskScheduler == null) {
|
||||
this.setMessagingTaskScheduler(createDefaultScheduler());
|
||||
if (this.executor == null) {
|
||||
this.executor = new ScheduledThreadPoolExecutor(DEFAULT_DISPATCHER_POOL_SIZE);
|
||||
}
|
||||
SimpleMessagingTaskScheduler scheduler = new SimpleMessagingTaskScheduler(this.executor);
|
||||
scheduler.setErrorHandler(new MessagePublishingErrorHandler(this.getErrorChannel()));
|
||||
this.taskScheduler = scheduler;
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private MessagingTaskScheduler createDefaultScheduler() {
|
||||
CustomizableThreadFactory threadFactory = new CustomizableThreadFactory();
|
||||
threadFactory.setThreadNamePrefix("dispatcher-executor-");
|
||||
threadFactory.setThreadGroup(new ThreadGroup("dispatcher-executors"));
|
||||
SimpleMessagingTaskScheduler scheduler = new SimpleMessagingTaskScheduler();
|
||||
scheduler.setCorePoolSize(this.dispatcherPoolSize);
|
||||
scheduler.setThreadFactory(threadFactory);
|
||||
scheduler.setErrorHandler(new MessagePublishingErrorHandler(this.getErrorChannel()));
|
||||
scheduler.afterPropertiesSet();
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public MessageChannel getErrorChannel() {
|
||||
return this.channelRegistry.getErrorChannel();
|
||||
}
|
||||
@@ -206,8 +189,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
|
||||
this.initialize();
|
||||
}
|
||||
channel.setName(name);
|
||||
DefaultMessageDispatcher dispatcher = new DefaultMessageDispatcher(channel);
|
||||
dispatcher.setMessagingTaskScheduler(this.taskScheduler);
|
||||
DefaultMessageDispatcher dispatcher = new DefaultMessageDispatcher(channel, this.taskScheduler);
|
||||
this.dispatchers.put(channel, dispatcher);
|
||||
this.channelRegistry.registerChannel(name, channel);
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
||||
@@ -27,15 +27,14 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.MessagingConfigurationException;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.scheduling.MessagingTask;
|
||||
import org.springframework.integration.scheduling.MessagingTaskScheduler;
|
||||
import org.springframework.integration.scheduling.MessagingTaskSchedulerAware;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.integration.scheduling.SimpleMessagingTaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -47,7 +46,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultMessageDispatcher implements SchedulingMessageDispatcher, MessagingTaskSchedulerAware {
|
||||
public class DefaultMessageDispatcher implements SchedulingMessageDispatcher {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
@@ -55,33 +54,28 @@ public class DefaultMessageDispatcher implements SchedulingMessageDispatcher, Me
|
||||
|
||||
private final MessageRetriever retriever;
|
||||
|
||||
private MessagingTaskScheduler scheduler;
|
||||
private final MessagingTaskScheduler scheduler;
|
||||
|
||||
private Schedule defaultSchedule = new PollingSchedule(5);
|
||||
private volatile Schedule defaultSchedule = new PollingSchedule(5);
|
||||
|
||||
private final ConcurrentMap<Schedule, List<MessageHandler>> scheduledHandlers = new ConcurrentHashMap<Schedule, List<MessageHandler>>();
|
||||
|
||||
private final AtomicLong totalMessagesProcessed = new AtomicLong();
|
||||
|
||||
private volatile boolean starting;
|
||||
|
||||
private volatile boolean running;
|
||||
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
|
||||
|
||||
public DefaultMessageDispatcher(MessageChannel channel) {
|
||||
public DefaultMessageDispatcher(MessageChannel channel, MessagingTaskScheduler scheduler) {
|
||||
Assert.notNull(channel, "'channel' must not be null");
|
||||
Assert.notNull(scheduler, "'scheduler' must not be null");
|
||||
this.channel = channel;
|
||||
this.scheduler = scheduler;
|
||||
this.retriever = new ChannelPollingMessageRetriever(this.channel);
|
||||
}
|
||||
|
||||
|
||||
public void setMessagingTaskScheduler(MessagingTaskScheduler scheduler) {
|
||||
Assert.notNull(scheduler, "'scheduler' must not be null");
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public void setDefaultSchedule(Schedule defaultSchedule) {
|
||||
Assert.notNull(defaultSchedule, "'defaultSchedule' must not be null");
|
||||
this.defaultSchedule = defaultSchedule;
|
||||
@@ -123,33 +117,23 @@ public class DefaultMessageDispatcher implements SchedulingMessageDispatcher, Me
|
||||
|
||||
public void start() {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
if (this.isRunning() || this.starting) {
|
||||
if (this.running) {
|
||||
return;
|
||||
}
|
||||
this.starting = true;
|
||||
}
|
||||
if (this.scheduler == null) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("no scheduler was provided, will create one");
|
||||
if (this.scheduler == null) {
|
||||
throw new MessagingConfigurationException("'scheduler' is required");
|
||||
}
|
||||
if (!this.scheduler.isRunning()) {
|
||||
this.scheduler.start();
|
||||
}
|
||||
this.scheduler = new SimpleMessagingTaskScheduler();
|
||||
}
|
||||
if (!this.scheduler.isRunning()) {
|
||||
this.scheduler.start();
|
||||
}
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
for (Schedule schedule : this.scheduledHandlers.keySet()) {
|
||||
scheduleDispatcherTask(schedule);
|
||||
}
|
||||
this.running = true;
|
||||
this.starting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleDispatcherTask(Schedule schedule) {
|
||||
if (!this.isRunning()) {
|
||||
this.start();
|
||||
}
|
||||
List<MessageHandler> handlers = this.scheduledHandlers.get(schedule);
|
||||
for (MessageHandler handler : handlers) {
|
||||
if (handler instanceof Lifecycle) {
|
||||
@@ -160,7 +144,7 @@ public class DefaultMessageDispatcher implements SchedulingMessageDispatcher, Me
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (!this.isRunning()) {
|
||||
if (!this.running) {
|
||||
return;
|
||||
}
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
|
||||
@@ -21,12 +21,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.util.ErrorHandler;
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -35,78 +32,60 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class SimpleMessagingTaskScheduler extends AbstractMessagingTaskScheduler implements InitializingBean {
|
||||
public class SimpleMessagingTaskScheduler extends AbstractMessagingTaskScheduler {
|
||||
|
||||
private ScheduledExecutorService executor;
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
private int corePoolSize = 10;
|
||||
private volatile ErrorHandler errorHandler;
|
||||
|
||||
private ThreadFactory threadFactory;
|
||||
private final Set<Runnable> pendingTasks = new CopyOnWriteArraySet<Runnable>();
|
||||
|
||||
private String threadNamePrefix = this.getClass().getSimpleName() + "-";
|
||||
|
||||
private ErrorHandler errorHandler;
|
||||
|
||||
private Set<Runnable> pendingTasks = new CopyOnWriteArraySet<Runnable>();
|
||||
private volatile boolean starting;
|
||||
|
||||
private volatile boolean running;
|
||||
|
||||
private Object lifecycleMonitor = new Object();
|
||||
private final Object lifecycleMonitor = new Object();
|
||||
|
||||
|
||||
public void setExecutor(ScheduledExecutorService executor) {
|
||||
public SimpleMessagingTaskScheduler(int corePoolSize) {
|
||||
this(new ScheduledThreadPoolExecutor(corePoolSize));
|
||||
}
|
||||
|
||||
public SimpleMessagingTaskScheduler(ScheduledExecutorService executor) {
|
||||
Assert.notNull(executor, "'executor' must not be null");
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public void setCorePoolSize(int corePoolSize) {
|
||||
Assert.isTrue(corePoolSize > 0, "'corePoolSize' must be greater than 0");
|
||||
this.corePoolSize = corePoolSize;
|
||||
}
|
||||
|
||||
public void setThreadFactory(ThreadFactory threadFactory) {
|
||||
this.threadFactory = threadFactory;
|
||||
}
|
||||
|
||||
public void setThreadNamePrefix(String threadNamePrefix) {
|
||||
Assert.notNull(threadNamePrefix, "'threadNamePrefix' must not be null");
|
||||
this.threadNamePrefix = threadNamePrefix;
|
||||
}
|
||||
|
||||
public void setErrorHandler(ErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.executor == null) {
|
||||
if (this.threadFactory == null) {
|
||||
this.threadFactory = new CustomizableThreadFactory(this.threadNamePrefix);
|
||||
}
|
||||
this.executor = new ScheduledThreadPoolExecutor(this.corePoolSize, this.threadFactory);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (this.executor == null) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
this.running = true;
|
||||
for (Runnable task : this.pendingTasks) {
|
||||
this.schedule(task);
|
||||
if (this.running || this.starting) {
|
||||
return;
|
||||
}
|
||||
this.pendingTasks.clear();
|
||||
this.starting = true;
|
||||
}
|
||||
for (Runnable task : this.pendingTasks) {
|
||||
this.schedule(task);
|
||||
}
|
||||
this.pendingTasks.clear();
|
||||
this.running = true;
|
||||
this.starting = false;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.isRunning()) {
|
||||
this.running = false;
|
||||
this.executor.shutdownNow();
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
if (this.running) {
|
||||
this.executor.shutdownNow();
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user