问题
In spring boot, can I schedule a spring job by not using @Scheduled
annotation to a method?
I am working with spring job in the spring boot. I want to schedule a job by using cron expression, but without using @Scheduled(cron = " ")
annotation to the method.
I know that I can schedule a job inside this method as below.
@Scheduled (cron = "0 10 10 10 * ?")
public void execute() {
/ * some job code * /
}
But I want it to be dynamic so that I can take a cron expression as input from the user and schedule it.
回答1:
I came up with a working example since I found your question interesting and have been interested in this problem before. It's based entirely on the source code so I have no idea if it comes close to following best practice. Nonetheless, you may be able to tune it to your needs. FYI, you don't necessarily need to create a new ScheduledTaskRegistrar object - I figured that since your objective is a dynamic scheduler, you wouldn't be interested in defining your tasks purely in the overwritten method.
@SpringBootApplication
public class TaskScheduler implements SchedulingConfigurer, CommandLineRunner {
public static void main(String[] args){SpringApplication.run(TaskScheduler.class, args);}
List<CronTask> cronTasks;
@Override
public void run(String... args) throws Exception {
CronTask task = this.createCronTask(new Runnable() {
@Override
public void run() {
System.out.println(LocalDateTime.now());
}
}, "1/10 * * * * *");
ScheduledTaskRegistrar taskRegistrar = new ScheduledTaskRegistrar();
taskRegistrar.addCronTask(task);
configureTasks(taskRegistrar);
Thread.sleep(51);
taskRegistrar.destroy();
taskRegistrar = null;
ScheduledTaskRegistrar taskRegistrar2 = new ScheduledTaskRegistrar();
taskRegistrar2.addCronTask(task);
configureTasks(taskRegistrar2);
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// "Calls scheduleTasks() at bean construction time" - docs
taskRegistrar.afterPropertiesSet();
}
public CronTask createCronTask(Runnable action, String expression) {
return new CronTask(action, new CronTrigger(expression));
}
}
I have experience using cron jobs in Azure and other places. Programming in Java, I have typically used @Scheduled
with fixed times just for the sake of simplicity. Hope this is useful to you though.
回答2:
Here is my working example, If somebody wants to use TaskScheduler without using @Scheduled Annotation
@Configuration Class
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
final Logger LOGGER = LogManager.getLogger(SchedulerConfig.class);
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
LOGGER.debug("Creating Async Task Scheduler");
scheduledTaskRegistrar.setTaskScheduler(taskScheduler());
}
// This is mandatory otherwise it will to be able to find bean of
// taskScheduler. Without this it was giving runtime error says, can not find
// taskScheduler bean.
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(20); // Better to read it from property file.
scheduler.setThreadNamePrefix("ThreadScheduler-");
scheduler.initialize();
return scheduler;
}
}
Scheduler Class which is called from Application class.
@Component
public class MyTaskScheduler {
private TaskScheduler taskScheduler;
// Here we are auto-wiring taskScheduler, that's why need to create
// taskScheduler bean in configuration class
@Autowired
public void setScheduler(TaskScheduler scheduler) {
this.taskScheduler = scheduler;
}
public void schedule() {
taskScheduler.scheduleWithFixedDelay(new Runnable(){
@Override
public void run() {
System.out.println("I am running after every 1 second");
}
}, 1000);
}
}
If in any chance @Configuration
annotation is not working so put @EnableConfigurationProperties
at main running class.
Make sure that you put @EnableScheduling
at Application
class, so main runnable class will look like
@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties
public class MainApplication implements CommandLineRunner {
@Autowired
MyTaskScheduler myTaskScheduler;
public static void main(String[] args) {
final Logger logger = LogManager.getLogger(MainApplication.class);
SpringApplication.run(MainApplication.class, args);
logger.info("Application started");
}
@Override
public void run(String... args) throws Exception {
myTaskScheduler.schedule();
}
}
来源:https://stackoverflow.com/questions/56938152/how-to-schedule-a-cron-job-in-spring-boot-without-using-scheduled-annotation