@예약 주석을 사용하여 시작된 예약된 작업을 중지하는 방법은 무엇입니까?
Spring Framework의 주석을 사용하여 간단한 예약 작업을 만들었습니다.
@Scheduled(fixedRate = 2000)
public void doSomething() {}
이제 더 이상 필요하지 않을 때 이 작업을 중지하고 싶습니다.
이 방법을 시작할 때 하나의 조건부 플래그를 확인하는 방법이 있을 수 있지만 이 방법의 실행이 중지되지는 않습니다.
스프링이 멈추기 위해 제공하는 것이 있습니까?@Scheduled과제?
옵션 1: 포스트 프로세서 사용
예약을 중지해야 하는 빈에 대해 제공하고 명시적으로 호출합니다.
옵션 2: 대상 원두의 미래 지도 유지
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;
}
}
빈에 대한 예약을 중지해야 할 경우 맵을 조회하여 해당하는 것을 가져오고 명시적으로 취소할 수 있습니다.
다음은 예약된 모든 실행 작업을 중지, 시작 및 나열할 수 있는 예입니다.
@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 !";
}
}
}
얼마 전 프로젝트에서 모든 구성 요소가 새 예약된 작업을 만들거나 스케줄러(모든 작업)를 중지할 수 있어야 한다는 요구 사항이 있었습니다.그래서 저는 이런 것을 했습니다.
@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;
}
}
그래서 저는 다음과 같은 것들을 할 수 있습니다.
Runnable task = new MyTask();
CentralScheduler.getInstance().start(task, 30_000L);
CentralScheduler.getInstance().stopAll();
어떤 이유에서인지, 저는 동시성에 대해 걱정할 필요 없이 그것을 했다는 것을 명심하세요.그렇지 않으면 동기화가 있어야 합니다.
@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;
}
}
이 질문에는 약간의 모호함이 있습니다.
- "이 작업을 중지"라고 하면 나중에 복구할 수 있는 방식으로 중지할 것을 의미합니까(예, 그렇다면 프로그래밍 방식으로 동일한 앱 내에서 발생하는 조건 사용)?아니면 외부 조건?)
- 같은 맥락에서 다른 작업을 실행하고 있습니까? (작업이 아닌 전체 앱을 종료할 수 있습니다.) -- 액추에이터를 사용할 수 있습니다.이 시나리오에서 끝점 종료
복구 가능한 방식으로 동일한 앱 내에서 발생할 수 있는 조건을 사용하여 작업을 종료하려고 하는 것이 가장 좋습니다.저는 이 가정을 바탕으로 답변을 시도하겠습니다.
이것은 제가 생각할 수 있는 가장 간단한 해결책입니다. 하지만 저는 중첩된 경우보다는 조기 반환과 같은 몇 가지 개선을 할 것입니다.
@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...
}
위 코드에 대한 속성
jobs.mediafiles.imagesPurgeJob.enable=true or false
jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?
제가 아직 찾지 못한 또 다른 접근법입니다.간편하고, 투명하며, 나사산이 안전합니다.
구성 클래스에 주석을 추가합니다.
@EnableScheduling예약된 작업을 시작/중지해야 하는 클래스의 다음 단계:
@Autowired TaskScheduler taskScheduler;필드 설정:
private ScheduledFuture yourTaskState; private long fixedRate = 1000L;스케줄링된 작업을 실행하는 내부 클래스를 만듭니다. 예:
class ScheduledTaskExecutor implements Runnable{ @Override public void run() { // task to be executed } }시작() 메서드 추가:
public void start(){ yourTaskState = taskScheduler.scheduleAtFixedRate(new ScheduledTaskExecutor(), fixedRate); }stop() 메서드 추가:
public void stop(){ yourTaskState.cancel(false); }
작업 스케줄러는 cron 또는 delay와 같은 다른 일반적인 스케줄링 방법을 제공합니다.
"ScheduledFutureisCancelled();
미니멀리스트 답변:
된 @1은 콩에 할 수 . @mahesh 1은 다음과 같습니다.
@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;
@Scheduled(fixedRate = 2000)
public void doSomething() {}
public void stopThis() {
postProcessBeforeDestruction(this, "")
}
또는 모든 콩에 대한 모든 작업을 취소할 수 있습니다.
@Autowired
private ThreadPoolTaskScheduler scheduler;
@Scheduled(fixedRate = 2000)
public void doSomething() {}
public void stopAll() {
scheduler.shutdown();
}
이전의 응답자 여러분, 저를 위해 이 문제를 해결해 주셔서 감사합니다.
예정된
스프링 공정 시Scheduled이 달린 각 방법을 합니다.
private final Map<Object, Set<ScheduledTask>> scheduledTasks =
new IdentityHashMap<Object, Set<ScheduledTask>>(16);
취소
반복적으로 예약된 작업을 취소하려면 다음과 같이 하면 됩니다(여기 내 레포에서 실행 가능한 데모가 있습니다).
@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;
@Autowired
private TestSchedule testSchedule;
public void later() {
postProcessor.postProcessBeforeDestruction(test, "testSchedule");
}
알려드립니다
그것은 이 콩들의 것을 찾을 것입니다.ScheduledTask그리고 하나씩 취소합니다.해야 할 중인 입니다.postProcessBeforeDestruction출처 표시).
synchronized (this.scheduledTasks) {
tasks = this.scheduledTasks.remove(bean); // remove from future running
}
if (tasks != null) {
for (ScheduledTask task : tasks) {
task.cancel(); // cancel current running method
}
}
아래와 같이 사용자 지정 주석을 정의합니다.
@Documented
@Retention (RUNTIME)
@Target(ElementType.TYPE)
public @interface ScheduledSwitch {
// do nothing
}
클래스 구현 org.springframework.scheduling.notation을 정의합니다.예약된 주석 BeanPostProcessor입니다.
public class ScheduledAnnotationBeanPostProcessorCustom
extends ScheduledAnnotationBeanPostProcessor {
@Value(value = "${prevent.scheduled.tasks:false}")
private boolean preventScheduledTasks;
private Map<Object, String> beans = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock(true);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
ScheduledSwitch switch = AopProxyUtils.ultimateTargetClass(bean)
.getAnnotation(ScheduledSwitch.class);
if (null != switch) {
beans.put(bean, beanName);
if (preventScheduledTasks) {
return bean;
}
}
return super.postProcessAfterInitialization(bean, beanName);
}
public void stop() {
lock.lock();
try {
for (Map.Entry<Object, String> entry : beans.entrySet()) {
postProcessBeforeDestruction(entry.getKey(), entry.getValue());
}
} finally {
lock.unlock();
}
}
public void start() {
lock.lock();
try {
for (Map.Entry<Object, String> entry : beans.entrySet()) {
if (!requiresDestruction(entry.getKey())) {
super.postProcessAfterInitialization(
entry.getKey(), entry.getValue());
}
}
} finally {
lock.unlock();
}
}
}
예약된 주석 BeanPostProcessor bean을 사용자 지정 bean 구성으로 바꿉니다.
@Configuration
public class ScheduledConfig {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationBeanPostProcessor() {
return new ScheduledAnnotationBeanPostProcessorCustom();
}
}
@ScheduledTasks를 방지하거나 중지할 빈에 @ScheduledSwitch 주석을 추가합니다.
용사를 합니다.@conditional조건 메소드의 값이 사실인지 확인하는 데 도움이 됩니까?스케줄러를 실행합니다.그렇지 않으면 뛰지 마.
그 인터페이스를 .matches방법
public class MyCondition implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetaData metadata) {
// here implement your condition using if-else or checking another object
// or call another method that can return boolean value
//return boolean value : true or false
return true;
}
}
다음 " " " " " " " " " " " " " " 를 합니다.@Scheduled
@Service
@Conditional(value = MyCondition.class)
// this Service will only run if the condition is true
public class scheduledTask {
// the @Scheduled method should be void
@Scheduled(fixedRate= 5000)
public void task(){
System.out.println(" This is scheduled task started....");
}
}
이것은 확실히 저에게 효과가 있었습니다.
import com.google.common.collect.Maps;
import org.redisson.liveobject.misc.ClassUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import static java.util.Collections.emptySet;
import com.google.common.collect.Maps;
import org.redisson.liveobject.misc.ClassUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import static java.util.Collections.emptySet;
/**
* @author uhfun
*/
@Component
public class ConfigurableScheduler {
private final InnerScheduledAnnotationBeanPostProcessor postProcessor;
public ConfigurableScheduler(InnerScheduledAnnotationBeanPostProcessor postProcessor) {
this.postProcessor = postProcessor;
}
public void registerScheduleTask(String cron, Method method, Object target) {
Map<String, Object> attributes = Maps.newHashMap();
attributes.put("cron", cron);
Scheduled scheduled = AnnotationUtils.synthesizeAnnotation(attributes, Scheduled.class, null);
postProcessor.registerScheduleTask(scheduled, method, target);
}
public void unregister(String cron, Object target) {
postProcessor.unregister(target, cron);
}
@Component
public static class InnerScheduledAnnotationBeanPostProcessor extends ScheduledAnnotationBeanPostProcessor {
private final Map<Object, Set<ScheduledTask>> scheduledTasksMap;
public InnerScheduledAnnotationBeanPostProcessor() {
scheduledTasksMap = ClassUtils.getField(this, "scheduledTasks");
}
public void registerScheduleTask(Scheduled scheduled, Method method, Object bean) {
super.processScheduled(scheduled, method, bean);
}
public void unregister(Object bean, String cron) {
synchronized (scheduledTasksMap) {
Set<ScheduledTask> tasks = getScheduledTasks();
for (ScheduledTask task : tasks) {
if (task.getTask() instanceof CronTask
&& ((CronTask) task.getTask()).getExpression().equals(cron)) {
task.cancel();
scheduledTasksMap.getOrDefault(bean, emptySet()).remove(task);
}
}
}
}
}
}
를 사용하는 것은 어떻습니까?System.exit(1)이것은 간단하고 효과적입니다.
언급URL : https://stackoverflow.com/questions/44644141/how-to-stop-a-scheduled-task-that-was-started-using-scheduled-annotation
'programing' 카테고리의 다른 글
| SqlConnection 또는 OracleConnection 대신 DbConnection을 사용하는 것이 어떻습니까? (0) | 2023.08.08 |
|---|---|
| mysql workbench 열 아이콘의 의미 (0) | 2023.08.08 |
| 하위 요소를 호버링할 때 상위 요소의 스타일을 지정하는 방법은 무엇입니까? (0) | 2023.08.08 |
| 시스템.Linq.IQueryable에 '위치'에 대한 정의가 없습니다. (0) | 2023.08.08 |
| ORM을 통해 SQLAlchemy 개체를 로드하는 것이 원시 MySQLDB 커서를 통해 행을 로드하는 것보다 느린 이유는 무엇입니까? (0) | 2023.08.08 |