Удаленный планировщик Spring Quartz

Я запустил экземпляр кварцевого сервера с помощью spring (как в статье), он работает хорошо. Но когда я пытаюсь запустить другое приложение с кварцевым клиентом и подключиться к кварцевому серверу, у меня возникает ошибка, пожалуйста, помогите, что я делаю неправильно.

Конфигурация сервера:

@Configuration
public class ServerConfig {
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(ApplicationContext applicationContext) {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
        schedulerFactory.setSchedulerListeners(...);
        schedulerFactory.setJobFactory(...);
        schedulerFactory.setTriggers(...);
        return schedulerFactory;
    }
    ...

}

Конфигурация клиента:

@Configuration
public class ClientConfig {
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
        schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
        return schedulerFactory;
    }
...
}

Сервер кварц.свойства:

org.quartz.scheduler.instanceName=myScheduler
org.quartz.scheduler.rmi.export=true
org.quartz.scheduler.rmi.createRegistry=true
org.quartz.scheduler.rmi.registryHost=localhost
org.quartz.scheduler.rmi.registryPort=1099
org.quartz.scheduler.rmi.serverPort=1100

Клиентские кварц.свойства:

org.quartz.scheduler.instanceName=myScheduler
org.quartz.scheduler.rmi.proxy=true
org.quartz.scheduler.rmi.registryHost=localhost
org.quartz.scheduler.rmi.registryPort=1099

Журналы сервера:

[2019-09-03] [10:07:26.171] INFO  SchedulerFactoryBean:538 - Loading Quartz config from [class path resource [quartz.properties]]
[2019-09-03] [10:07:26.229] INFO  StdSchedulerFactory:1208 - Using default implementation for ThreadExecutor
[2019-09-03] [10:07:26.272] INFO  SchedulerSignalerImpl:61 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[2019-09-03] [10:07:26.273] INFO  QuartzScheduler:229 - Quartz Scheduler v.2.3.0 created.
[2019-09-03] [10:07:26.277] INFO  RAMJobStore:155 - RAMJobStore initialized.
[2019-09-03] [10:07:26.338] INFO  QuartzScheduler:421 - Scheduler bound to RMI registry under name 'schedulerFactoryBean_$_NON_CLUSTERED'
[2019-09-03] [10:07:26.343] INFO  QuartzScheduler:294 - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - access via RMI.
...
[2019-09-03] [10:07:26.344] INFO  StdSchedulerFactory:1362 - Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance.
[2019-09-03] [10:07:26.345] INFO  StdSchedulerFactory:1366 - Quartz scheduler version: 2.3.0
...
[2019-09-03] [10:07:29.12] INFO  SchedulerFactoryBean:684 - Starting Quartz Scheduler now
[2019-09-03] [10:07:29.13] INFO  QuartzScheduler:547 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED started.

Логи клиента:

[2019-09-03] [10:11:53.255] INFO  SchedulerFactoryBean:538 - Loading Quartz config from [class path resource [quartz.properties]]
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactoryBean' defined in class path resource [com/mypackage/ClientConfig.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Operation not supported for remote schedulers.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1631)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
    ... 3 more
Caused by: org.quartz.SchedulerException: Operation not supported for remote schedulers.
    at org.quartz.impl.RemoteScheduler.getListenerManager(RemoteScheduler.java:913)
    at org.springframework.scheduling.quartz.SchedulerAccessor.registerListeners(SchedulerAccessor.java:340)
    at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:476)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1689)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1627)
    ... 13 more

Как видите, ошибка: org.quartz.SchedulerException: Operation not supported for remote schedulers. и происходит при инициализации бина. Что с этим не так?

После того, как клиент не запускается, сервер показывает в журналах:

[2019-09-03] [10:11:53.462] INFO  QuartzScheduler:666 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down.
[2019-09-03] [10:11:53.462] INFO  QuartzScheduler:585 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused.
[2019-09-03] [10:11:53.871] INFO  QuartzScheduler:447 - Scheduler un-bound from name 'schedulerFactoryBean_$_NON_CLUSTERED' in RMI registry
[2019-09-03] [10:11:53.872] INFO  QuartzScheduler:740 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutdown complete.

У меня версии Spring - 4.3.20, Quartz - 2.3.0

Обновление: я вижу registerListeners() вызов в SchedulerFactoryBean:

@Override
public void afterPropertiesSet() throws Exception {
        ...
        try {
            registerListeners();
            registerJobsAndTriggers();
        }
        catch (Exception ex) {
            try {
                this.scheduler.shutdown(true);
            }
            catch (Exception ex2) {
                logger.debug("Scheduler shutdown exception after registration failure", ex2);
            }
            throw ex;
        }
}

и в registerListeners() мы вызываем getScheduler().getListenerManager(), который терпит неудачу с исключением Operation not supported for remote schedulers. Как избежать вызова registerListeners() для RemoteScheduler?


person kio21    schedule 03.09.2019    source источник
comment
Вы видели Operation not supported for remote schedulers? Это имеет для вас значение?   -  person Jim Garrison    schedule 03.09.2019
comment
@JimGarrison Я вижу, что он срабатывает во время инициализации компонента, и я пока не выполняю никаких действий с клиентским компонентом.   -  person kio21    schedule 03.09.2019


Ответы (1)


Наконец, я получаю это следующим образом:

  • Я отказался от использования Spring SchedulerFactoryBean на клиенте, но вместо этого я напрямую создаю экземпляр StdSchedulerFactory из библиотеки кварца (затем он правильно создает экземпляр RemoteScheduler): new StdSchedulerFactory(). Он правильно подключается к экземпляру кварца сервера.

  • Из-за того, что я не могу получить экземпляр StdSchedulerFactory из SchedulerFactoryBean, я просто передаю оба компонента там, где это необходимо. Таким образом, в клиентском приложении SchedulerFactoryBean равно нулю, а в серверном приложении StdSchedulerFactory равно нулю.

  • Часть расписания заданий одинакова для обеих фабрик, так как все, что я делаю с ними, это получение планировщика:

private Scheduler getScheduler() throws SchedulerException {
    if (schedulerFactoryBean != null) return schedulerFactoryBean.getScheduler();
    if (schedulerFactory != null) return schedulerFactory.getScheduler();
    else return null;
}

а потом...

Scheduler scheduler = getScheduler();
if (scheduler != null) {
    scheduler.scheduleJob(job, trigger);
}
person kio21    schedule 06.09.2019