我实现了Spring-TaskExecutor(相当于JDK 1.5的Executor。)来处理从外部系统接收的通知通知。
只有一种方法的接口:
public interface AsynchronousService {
void executeAsynchronously(Runnable task);
}
和相应的实现:
public class AsynchronousServiceImpl implements AsynchronousService {
private Executor taskExecutor;
@Override
public void executeAsynchronously(Runnable task) {
taskExecutor.execute(task);
}
@Required
public void setTaskExecutor(Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
}
任务执行器(旧版应用程序)的Xml配置:
<bean id="taskExecutor" class="org.example.impl.NotificationPool">
<property name="corePoolSize" value="1"/>
<property name="maxPoolSize" value="1"/>
<property name="queueCapacity" value="100"/>
<property name="WaitForTasksToCompleteOnShutdown" value="true"/>
</bean>
为corePoolSize和maxPoolSize都设置了1,因为我希望任务按顺序执行(处理任务的池仅创建1个线程)。
我想根据收到通知的日期对任务进行排序,因此我需要重写此功能以允许优先级排序:
public class NotificationPool extends ThreadPoolExecutorFactoryBean{
@Override
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
return new PriorityBlockingQueue<>(queueCapacity);
}
}
ThreadPoolExecutorFactoryBean公开了“ createExecutor”方法,我确实重写了该方法以创建我们自己的Executor:
@Override
protected ThreadPoolExecutor createExecutor(int corePoolSize, int maxPoolSize, int keepAliveSeconds,
BlockingQueue<Runnable> queue, ThreadFactory threadFactory,
RejectedExecutionHandler rejectedExecutionHandler) {
return new YourCustomThreadPoolExecutor (corePoolSize, maxPoolSize, keepAliveSeconds, TimeUnit.SECONDS, queue,
threadFactory, rejectedExecutionHandler);
现在,在我的自定义线程池执行程序中,我可以覆盖默认的afterExecute回调:
public class YourCustomThreadPoolExecutor extends ThreadPoolExecutor {
public YourCustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
// Here do something with your exception
}
}
这是Notification任务类:
public class NotificationTask implements Runnable, Comparable<NotificationTask> {
private final NotificationService notificationService;
private final Notification notification;
public NotificationService(NotificationService notificationService,
Notification notification) {
this.notificationService = notificationService;
this.notification = notification;
}
@Override
public int compareTo(NotificationTask task) {
return notification.getTimestamp().compareTo(task.getTimestamp());
}
@Override
public void run() {
notificationService.processNotification(notification);
}
}
这就是我的执行方式:
asynchronousService.executeAsynchronously(new NotificationTask (notificationService, notification));
我不仅希望将队列存储在内存中,而且还希望将任务持久存储在数据库中,所以即使应用程序崩溃,我也可以拥有它们。
我想到的第一个解决方案是覆盖beforeExecute
类中的默认YourCustomThreadPoolExecutor
回调:
public class YourCustomThreadPoolExecutor extends ThreadPoolExecutor {
public YourCustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
// 1) serialize runnable object
// 2) write in the database (with a flag if it is executed true/false)
super.beforeExecute(t, r);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
}
}
现在的想法是,当我执行任务时,我将首先检查数据库,如果它存在未执行的任务(例如,通过检查布尔标志)。如果是,那么我首先获得此任务并执行它并更新标志。然后,我继续执行其他任务。因此,在这种情况下,如果应用程序在执行任务后崩溃,那么我仍然确保在应用程序再次运行后执行该任务,它不会丢失。您如何看待该解决方案?
首先,我试图找到一个挂接方法,然后将该任务放入队列,因此可以在其中执行任务的持久性。 (因为我宁愿在将任务放入队列之前先保留任务),但是我没有找到任何方法可以执行此操作,因此,我唯一的机会就是重写beforeExecutue
方法。这当然不是很理想,因为我只是在将任务出队时才开始保留任务,因此如果应用程序崩溃,队列中的所有任务都会丢失。