복붙노트

[SPRING] TaskScheduler, @Scheduled 및 석영

SPRING

TaskScheduler, @Scheduled 및 석영

기본 스케쥴러로 @Scheduled를 석영으로 만드는 방법이 있습니까?

내가 생각할 수있는 두 가지,하지만 둘 다 몇 가지 작업이 필요합니다.

질문 : 위의 두 가지 옵션에 대해 이미 작성된 것이 있고 또 다른 옵션이 있습니까?

해결법

  1. ==============================

    1.나는 내 자신의 봄 석영 "다리"를 만들었습니다. 나는 봄에 대한 개선으로 제안 할 계획이다.

    나는 내 자신의 봄 석영 "다리"를 만들었습니다. 나는 봄에 대한 개선으로 제안 할 계획이다.

    먼저 quartz Job 인터페이스를 구현하는 클래스에 배치 할 새로운 주석을 작성했다.

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Component
    @Scope("prototype")
    public @interface ScheduledJob {
        String cronExpression() default "";
        long fixedRate() default -1;
        boolean durable() default false;
        boolean shouldRecover() default true;
        String name() default "";
        String group() default "";
    }
    

    (프로토 타입 범위 - 쿼츠는 각 인스턴스의 실행이 새로운 인스턴스라고 가정합니다. 저는 쿼츠 전문가가 아니므로 기대에 부합했습니다. 중복 된 경우 @Scope 주석을 제거하면됩니다)

    그런 다음 컨텍스트가 새로 고쳐지거나 시작될 때마다 @ScheduledJob으로 주석 처리 된 모든 클래스를 찾아 쿼츠 스케줄러에 등록 할 때 ApplicationListener를 정의했습니다.

    /**
     * This class listeners to ContextStartedEvent, and when the context is started
     * gets all bean definitions, looks for the @ScheduledJob annotation,
     * and registers quartz jobs based on that.
     *
     * Note that a new instance of the quartz job class is created on each execution,
     * so the bean has to be of "prototype" scope. Therefore an applicationListener is used
     * rather than a bean postprocessor (unlike singleton beans, prototype beans don't get
     * created on application startup)
     *
     * @author bozho
     *
     */
     public class QuartzScheduledJobRegistrar implements
        EmbeddedValueResolverAware, ApplicationContextAware,
        ApplicationListener<ContextRefreshedEvent> {
    
    private Scheduler scheduler;
    
    private StringValueResolver embeddedValueResolver;
    
    private Map<JobListener, String> jobListeners;
    
    private ApplicationContext applicationContext;
    
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.embeddedValueResolver = resolver;
    }
    
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext() == this.applicationContext) {
            try {
                scheduler.clear();
    
                for (Map.Entry<JobListener, String> entry : jobListeners.entrySet()) {
                    scheduler.getListenerManager().addJobListener(entry.getKey(), NameMatcher.nameStartsWith(entry.getValue()));
                }
            } catch (SchedulerException ex) {
                throw new IllegalStateException(ex);
            }
    
            DefaultListableBeanFactory factory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
            String[] definitionNames = factory.getBeanDefinitionNames();
            for (String definitionName : definitionNames) {
                BeanDefinition definition = factory.getBeanDefinition(definitionName);
                try {
                    if (definition.getBeanClassName() != null) {
                        Class<?> beanClass = Class.forName(definition.getBeanClassName());
                        registerJob(beanClass);
                    }
                } catch (ClassNotFoundException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        }
    }
    
    public void registerJob(Class<?> targetClass) {
        ScheduledJob annotation = targetClass.getAnnotation(ScheduledJob.class);
    
        if (annotation != null) {
            Assert.isTrue(Job.class.isAssignableFrom(targetClass),
                    "Only classes implementing the quartz Job interface can be annotated with @ScheduledJob");
    
            @SuppressWarnings("unchecked") // checked on the previous line
            Class<? extends Job> jobClass = (Class<? extends Job>) targetClass;
    
            JobDetail jobDetail = JobBuilder.newJob()
                .ofType(jobClass)
                .withIdentity(
                        annotation.name().isEmpty() ? targetClass.getSimpleName() : annotation.name(),
                        annotation.group().isEmpty() ? targetClass.getPackage().getName() : annotation.group())
                .storeDurably(annotation.durable())
                .requestRecovery(annotation.shouldRecover())
                .build();
    
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger()
                .withIdentity(jobDetail.getKey().getName() + "_trigger", jobDetail.getKey().getGroup() + "_triggers")
                .startNow();
    
            String cronExpression = annotation.cronExpression();
            long fixedRate = annotation.fixedRate();
            if (!BooleanUtils.xor(new boolean[] {!cronExpression.isEmpty(), fixedRate >=0})) {
                throw new IllegalStateException("Exactly one of 'cronExpression', 'fixedRate' is required. Offending class " + targetClass.getName());
            }
    
            if (!cronExpression.isEmpty()) {
                if (embeddedValueResolver != null) {
                    cronExpression = embeddedValueResolver.resolveStringValue(cronExpression);
                }
                try {
                    triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
                } catch (ParseException e) {
                    throw new IllegalArgumentException(e);
                }
            }
    
    
            if (fixedRate >= 0) {
                triggerBuilder.withSchedule(
                            SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInMilliseconds(fixedRate)
                                .repeatForever())
                    .withIdentity(jobDetail.getKey().getName() + "_trigger", jobDetail.getKey().getGroup() + "_triggers");
            }
    
            try {
                scheduler.scheduleJob(jobDetail, triggerBuilder.build());
            } catch (SchedulerException e) {
                throw new IllegalStateException(e);
            }
        }
    }
    
    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }
    
    public void setJobListeners(Map<JobListener, String> jobListeners) {
        this.jobListeners = jobListeners;
    }
    }
    

    그런 다음 커스텀 JobFactory를 사용하여 석영을 플러그인하여 봄 컨텍스트로 작업을 생성해야했습니다.

    public class QuartzSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    
    private SchedulerContext schedulerContext;
    private ApplicationContext ctx;
    
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Job job = ctx.getBean(bundle.getJobDetail().getJobClass());
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
        MutablePropertyValues pvs = new MutablePropertyValues();
        pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
        pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
        if (this.schedulerContext != null) {
            pvs.addPropertyValues(this.schedulerContext);
        }
        bw.setPropertyValues(pvs, true);
        return job;
    }
    
    public void setSchedulerContext(SchedulerContext schedulerContext) {
        this.schedulerContext = schedulerContext;
        super.setSchedulerContext(schedulerContext);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.ctx = applicationContext;
    }
    }
    

    마지막으로, xml 설정 :

        <bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobFactory">
            <bean class="com.foo.bar.scheduling.QuartzSpringBeanJobFactory" />
        </property>
    </bean>
    
    <bean id="scheduledJobRegistrar" class="com.foo.bar.scheduling.QuartzScheduledJobRegistrar">
        <property name="scheduler" ref="quartzScheduler" />
        <property name="jobListeners">
            <map>
                <entry value=""> <!-- empty string = match all jobs -->
                    <key><bean class="com.foo.bar.scheduling.FailuresJobListener"/></key>
                </entry>
            </map>
        </property>
    </bean>
    
  2. ==============================

    2.준비된 구현이없는 것처럼 보입니다. 그러나, 당신 자신의 배선은 매우 어렵지 않아야합니다 :

    준비된 구현이없는 것처럼 보입니다. 그러나, 당신 자신의 배선은 매우 어렵지 않아야합니다 :

    @Service
    public class QuartzTaskScheduler implements TaskScheduler {
        //...
    }
    

    Spring이 그것을 사용하게 만들기 :

    <task:annotation-driven/>
    
    <bean class="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor">
        <property name="scheduler" ref="quartzTaskScheduler"/>
    </bean>
    

    이 경로를 따라 간다면 스프링 프레임 워크 (org.springframework.scheduling.quartz 패키지)에 코드를 제공하거나 최소한 그 문제를 열어 볼 수있다.

  3. from https://stackoverflow.com/questions/6788811/taskscheduler-scheduled-and-quartz by cc-by-sa and MIT license