Sac*_*141 31 java spring scheduled-tasks
我使用Spring Framework的@Scheduled注释创建了一个简单的计划任务.
@Scheduled(fixedRate = 2000)
public void doSomething() {}
Run Code Online (Sandbox Code Playgroud)
现在我想在不再需要时停止这项任务.
我知道在这个方法的开头可以有一个替代方法来检查一个条件标志,但是这不会停止执行这个方法.
Spring提供什么来阻止@Scheduled任务?
Mah*_*esh 18
为应该停止调度的bean 提供ScheduledAnnotationBeanPostProcessor并显式调用postProcessBeforeDestruction(Object bean, String beanName).
private final Map<Object, ScheduledFuture<?>> scheduledTasks =
new IdentityHashMap<>();
@Scheduled(fixedRate = 2000)
public void fixedRateJob() {
System.out.println("Something to be done every 2 secs");
}
@Bean
public TaskScheduler poolScheduler() {
return new CustomTaskScheduler();
}
class CustomTaskScheduler extends ThreadPoolTaskScheduler {
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
ScheduledFuture<?> future = super.scheduleAtFixedRate(task, period);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
scheduledTasks.put(runnable.getTarget(), future);
return future;
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
ScheduledFuture<?> future = super.scheduleAtFixedRate(task, startTime, period);
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
scheduledTasks.put(runnable.getTarget(), future);
return future;
}
}
Run Code Online (Sandbox Code Playgroud)
当必须停止bean的调度时,您可以查找映射以获取对应的映射Future并显式取消它.
@Mahesh 选项 1 的工作示例实现,使用ScheduledAnnotationBeanPostProcessor.postProcessBeforeDestruction(bean, beanName).
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
public class ScheduledTaskExample implements ApplicationContextAware, BeanNameAware
{
private ApplicationContext applicationContext;
private String beanName;
@Scheduled(fixedDelay = 1000)
public void someTask()
{
/* Do stuff */
if (stopScheduledTaskCondition)
{
stopScheduledTask();
}
}
private void stopScheduledTask()
{
ScheduledAnnotationBeanPostProcessor bean = applicationContext.getBean(ScheduledAnnotationBeanPostProcessor.class);
bean.postProcessBeforeDestruction(this, beanName);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
{
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String beanName)
{
this.beanName = beanName;
}
}
Run Code Online (Sandbox Code Playgroud)
这个问题有点含糊不清
我最好的猜测是,您希望使用可能以可恢复的方式在同一个应用程序中出现的条件来关闭任务.我会尝试根据这个假设回答.
这是最简单的可能,我能想到的解决方案,不过,我会做出这样提前返回了一些改进,而不是嵌套如果小号
@Component
public class SomeScheduledJob implements Job {
private static final Logger LOGGER = LoggerFactory.getLogger(SomeScheduledJob.class);
@Value("${jobs.mediafiles.imagesPurgeJob.enable}")
private boolean imagesPurgeJobEnable;
@Override
@Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
public void execute() {
if(!imagesPurgeJobEnable){
return;
}
Do your conditional job here...
}
Run Code Online (Sandbox Code Playgroud)
上述代码的属性
jobs.mediafiles.imagesPurgeJob.enable=true or false
jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?
Run Code Online (Sandbox Code Playgroud)
这是一个示例,我们可以停止,启动和列出所有计划的运行任务:
@RestController
@RequestMapping("/test")
public class TestController {
private static final String SCHEDULED_TASKS = "scheduledTasks";
@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;
@Autowired
private ScheduledTasks scheduledTasks;
@Autowired
private ObjectMapper objectMapper;
@GetMapping(value = "/stopScheduler")
public String stopSchedule(){
postProcessor.postProcessBeforeDestruction(scheduledTasks, SCHEDULED_TASKS);
return "OK";
}
@GetMapping(value = "/startScheduler")
public String startSchedule(){
postProcessor.postProcessAfterInitialization(scheduledTasks, SCHEDULED_TASKS);
return "OK";
}
@GetMapping(value = "/listScheduler")
public String listSchedules() throws JsonProcessingException{
Set<ScheduledTask> setTasks = postProcessor.getScheduledTasks();
if(!setTasks.isEmpty()){
return objectMapper.writeValueAsString(setTasks);
}else{
return "No running tasks !";
}
}
Run Code Online (Sandbox Code Playgroud)
}
小智 6
我还没有找到另一种方法。简单、清晰且线程安全。
在您的配置类中添加注释:
@EnableScheduling
在您的班级中,您需要启动/停止计划任务注入的这一步和下一步:
@Autowired TaskScheduler taskScheduler;
设置字段:
private ScheduledFuture yourTaskState;
private long fixedRate = 1000L;
Run Code Online (Sandbox Code Playgroud)
创建执行计划任务的内部类,例如:
class ScheduledTaskExecutor implements Runnable{
@Override
public void run() {
// task to be executed
}
}
Run Code Online (Sandbox Code Playgroud)
添加start()方法:
public void start(){
yourTaskState = taskScheduler.scheduleAtFixedRate(new ScheduledTaskExecutor(), fixedRate);
}
Run Code Online (Sandbox Code Playgroud)
添加 stop() 方法:
public void stop(){
yourTaskState.cancel(false);
}
Run Code Online (Sandbox Code Playgroud)
TaskScheduler 提供了其他常见的调度方式,例如:cron 或延迟。
ScheduledFuture 还提供isCancelled();
不久前,我在项目中有一个要求,即任何组件都应该能够创建新的计划任务或停止计划程序(所有任务)。所以我做了这样的事情
@Configuration
@EnableScheduling
@ComponentScan
@Component
public class CentralScheduler {
private static AnnotationConfigApplicationContext CONTEXT = null;
@Autowired
private ThreadPoolTaskScheduler scheduler;
public static CentralScheduler getInstance() {
if (!isValidBean()) {
CONTEXT = new AnnotationConfigApplicationContext(CentralScheduler.class);
}
return CONTEXT.getBean(CentralScheduler.class);
}
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
return new ThreadPoolTaskScheduler();
}
public void start(Runnable task, String scheduleExpression) throws Exception {
scheduler.schedule(task, new CronTrigger(scheduleExpression));
}
public void start(Runnable task, Long delay) throws Exception {
scheduler.scheduleWithFixedDelay(task, delay);
}
public void stopAll() {
scheduler.shutdown();
CONTEXT.close();
}
private static boolean isValidBean() {
if (CONTEXT == null || !CONTEXT.isActive()) {
return false;
}
try {
CONTEXT.getBean(CentralScheduler.class);
} catch (NoSuchBeanDefinitionException ex) {
return false;
}
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
所以我可以做类似的事情
Runnable task = new MyTask();
CentralScheduler.getInstance().start(task, 30_000L);
CentralScheduler.getInstance().stopAll();
Run Code Online (Sandbox Code Playgroud)
请记住,出于某些原因,我这样做时不必担心并发性。否则应进行一些同步。
| 归档时间: |
|
| 查看次数: |
28245 次 |
| 最近记录: |