首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@RefreshScope停止@定时任务

@RefreshScope停止@定时任务
EN

Stack Overflow用户
提问于 2018-05-21 08:05:05
回答 4查看 4.3K关注 0票数 3

我有一个监控应用程序,其中我正在运行一个fixedRate任务。这是通过Consul配置的配置参数。我想引入更新的配置,所以我添加了@RefreshScope。但是,只要我更新Consul上的配置值,fixedRate任务就会停止运行。

代码语言:javascript
复制
@Service
@RefreshScope
public class MonitorService {

    @Autowired
    private AppConfig appConfig;

    @PostConstruct
    public void postConstRun() {
        System.out.println(appConfig.getMonitorConfig());
    }

    @Scheduled(fixedRate = 1000)
    public void scheduledMonitorScan() {
        System.out.println("MonitorConfig:" + appConfig.getMonitorConfig());
    }
}

AppConfig类只有一个字符串参数:

代码语言:javascript
复制
@Configuration
@Getter
@Setter
public class AppConfig {

    @Value("${monitor-config:default value}")
    private String monitorConfig;
}

一旦我更新了consul中的值,计划任务就停止运行(在sheduledMonitorScan方法中显示)停止显示。

EN

回答 4

Stack Overflow用户

发布于 2019-05-31 22:57:17

下面是我们解决这个问题的方法。

代码语言:javascript
复制
/**
 * Listener of Spring's lifecycle to revive Scheduler beans, when spring's
 * scope is refreshed.
 * <p>
 * Spring is able to restart beans, when we change their properties. Such a
 * beans marked with RefreshScope annotation. To make it work, spring creates
 * <b>lazy</b> proxies and push them instead of real object. The issue with
 * scope refresh is that right after refresh in order for such a lazy proxy
 * to be actually instantiated again someone has to call for any method of it.
 * <p>
 * It creates a tricky case with Schedulers, because there is no bean, which
 * directly call anything on any Scheduler. Scheduler lifecycle is to start
 * few threads upon instantiation and schedule tasks. No other bean needs
 * anything from them.
 * <p>
 * To overcome this, we had to create artificial method on Schedulers and call
 * them, when there is a scope refresh event. This actually instantiates.
 */
@RequiredArgsConstructor
public class RefreshScopeListener implements ApplicationListener<RefreshScopeRefreshedEvent> {
    private final List<RefreshScheduler> refreshSchedulers;

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        refreshSchedulers.forEach(RefreshScheduler::materializeAfterRefresh);
    }
}

因此,我们定义了一个接口,它不做任何特别的事情,但允许我们调用一个刷新的作业。

代码语言:javascript
复制
public interface RefreshScheduler {
    /**
     * Used after refresh context for scheduler bean initialization
     */
    default void materializeAfterRefresh() {
    }
}

这是实际的job,它的参数from.properties可以刷新。

代码语言:javascript
复制
public class AJob implements RefreshScheduler {
    @Scheduled(cron = "${from.properties}")
    public void aTask() {
        // do something useful
    }
}

更新:当然,AJob bean必须在@Configuration中标记为@RefreshScope

代码语言:javascript
复制
@Configuration
@EnableScheduling
public class SchedulingConfiguration {
    @Bean
    @RefreshScope
    public AJob aJob() {
        return new AJob();
    }
}
票数 4
EN

Stack Overflow用户

发布于 2020-08-07 23:24:49

我使用RefreshScopeRefreshedEvent成功地从consul config server获取并覆盖了这些值

代码语言:javascript
复制
import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RefreshScope
public class AlertSchedulerCron implements ApplicationListener<RefreshScopeRefreshedEvent> {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Value("${pollingtime}")
    private String pollingtime;
    
    /*
     * @Value("${interval}") private String interval;
     */
    @Scheduled(cron = "${pollingtime}")
    //@Scheduled(fixedRateString = "${interval}" )
    public void task() {

        System.out.println(pollingtime);
        System.out.println("Scheduler (cron expression) task with duration : " + sdf.format(new Date()));
    }

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
        // TODO Auto-generated method stub
        
    }

    
}
票数 4
EN

Stack Overflow用户

发布于 2018-09-27 19:46:58

我已经通过实现SchedulingConfigurer接口解决了这种情况。在这里,我从外部属性文件中动态更新"scheduler.interval“属性,即使在执行器刷新之后,调度器也能正常工作,因为我不再使用@ refresh anymore。希望这也能对你的情况有所帮助。

代码语言:javascript
复制
public class MySchedulerImpl implements SchedulingConfigurer {

    @Autowired
    private Environment env;

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }

    @Override
    public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(this.taskExecutor());
        taskRegistrar.addTriggerTask(() -> {
            //put your code here that to be scheduled
        }, triggerContext -> {
            final Calendar nextExecutionTime = new GregorianCalendar();
            final Date lastActualExecutionTime = triggerContext.lastActualExecutionTime();

            if (lastActualExecutionTime == null) {
                nextExecutionTime.setTime(new Date());
            } else {
                nextExecutionTime.setTime(lastActualExecutionTime);
                nextExecutionTime.add(Calendar.MILLISECOND, env.getProperty("scheduler.interval", Integer.class));
            }
            return nextExecutionTime.getTime();
        });
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50440468

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档