2015-01-25 15 views
8

W aplikacji, ponieważ przekonwertowałem ją z klasycznej wiosennej aplikacji webowej (wdrożonej w systemie Tomcat) do aplikacji Spring Boot (V1.2.1), napotykam problem, że Planowane prace kwarcowe już nie działają.Spring Boot: Używanie @Service w realizacji kwarcu

zaplanować te zadania Quartz tak:

// My own Schedule object which holds data about what to schedule when 
Schedule schedule = scheduleService.get(id of the schedule); 

String scheduleId = schedule.getId(); 

JobKey jobKey = new JobKey(scheduleId); 
TriggerKey triggerKey = new TriggerKey(scheduleId); 

JobDataMap jobData = new JobDataMap(); 
jobData.put("scheduleId", scheduleId); 

JobBuilder jobBuilder = JobBuilder.newJob(ScheduledActionRunner.class) 
    .withIdentity(jobKey) 
    .withDescription(schedule.getName()) 
    .usingJobData(jobData); 

JobDetail job = jobBuilder.build(); 

TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger() 
    .forJob(jobKey) 
    .withIdentity(triggerKey) 
    .withDescription(schedule.getName()); 

triggerBuilder = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.toCronExpression())); 

Trigger trigger = triggerBuilder.build(); 

org.quartz.Scheduler scheduler = schedulerFactoryBean.getScheduler(); 

scheduler.scheduleJob(job, trigger); 

ScheduledActionRunner:

@Component 
public class ScheduledActionRunner extends QuartzJobBean { 

    @Autowired 
    private ScheduleService scheduleService; 

    public ScheduledActionRunner() { 
    } 

    @Override 
    public void executeInternal(final JobExecutionContext context) throws JobExecutionException { 
     SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
     final JobDataMap jobDataMap = context.getMergedJobDataMap(); 
     final String scheduleId = jobDataMap.getString("scheduleId"); 
     final Schedule schedule = scheduleService.get(scheduleId); 
     // here it goes BANG since scheduleService is null 
    } 
} 

ScheduleService to klasyczny serwis Wiosna, która pobiera dane z Hibernate. Jak wspomniałem powyżej, działało to dobrze, dopóki nie przeniosłem się do Spring Boot.

Kiedy zaimplementowałem ten kod za pomocą klasycznej aplikacji Spring, SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); podjął się pomocy przy autowirowaniu usługi.

Co jest potrzebne, aby ponownie zadziałało w środowisku Spring Boot?

Edit:

W końcu zdecydowałem się odejść od korzystania Quartz na rzecz kodu sprężyny ThreadPoolTaskScheduler.The był znacznie uproszczony i działa zgodnie z oczekiwaniami.

+0

Komentarz do odpowiedzi z (!) Dewfy (ponieważ nie mam wystarczającej liczby osób do skomentowania): Musiałem również oznaczyć tę metodę adnotacją @Transactional, ponieważ dostałem błąd, że sesja hibernacji nie została dołączona. – gooboo

Odpowiedz

11

SpringBeanAutowiringSupport wykorzystuje kontekst aplikacji internetowej, który nie jest dostępny w twoim przypadku. Jeśli potrzebujesz kwarcu z fasolą wiosenną, powinieneś użyć kwarcowy wspornik dostarczony przez sprężynę. Zapewni to pełny dostęp do wszystkich zarządzanych komponentów. Aby uzyskać więcej informacji, patrz sekcja kwarcu na wiosnę docs pod numerem http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html. Zobacz także poniższy przykład zastosowania kwarcu z ziarnami fasoli uprawianej na wiosnę. Przykład oparty jest na Twoim kodzie. Dzięki temu możesz zmienić pierwszy fragment kodu (gdzie następuje inicjalizacja kwarcu) za pomocą kolejnych alternatyw sprężynowych.

Tworzenie szczegółu praca fabryki

@Component 
public class ScheduledActionRunnerJobDetailFactory extends JobDetailFactoryBean { 

    @Autowired 
    private ScheduleService scheduleService; 

    @Override 
    public void afterPropertiesSet() { 
     setJobClass(ScheduledActionRunner.class); 
     Map<String, Object> data = new HashMap<String, Object>(); 
     data.put("scheduleService", scheduleService); 
     setJobDataAsMap(data); 
     super.afterPropertiesSet(); 
    } 
} 

utworzyć fabrykę wyzwalania

@Component 
public class ActionCronTriggerFactoryBean extends CronTriggerFactoryBean { 

    @Autowired 
    private ScheduledActionRunnerJobDetailFactory jobDetailFactory; 

    @Value("${cron.pattern}") 
    private String pattern; 

    @Override 
    public void afterPropertiesSet() throws ParseException { 
     setCronExpression(pattern); 
     setJobDetail(jobDetailFactory.getObject()); 
     super.afterPropertiesSet(); 
    } 

} 

I wreszcie stworzyć SchedulerFactory

@Component 
public class ActionSchedulerFactoryBean extends SchedulerFactoryBean { 

    @Autowired 
    private ScheduledActionRunnerJobDetailFactory jobDetailFactory; 

    @Autowired 
    private ActionCronTriggerFactoryBean triggerFactory; 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     setJobDetails(jobDetailFactory.getObject()); 
     setTriggers(triggerFactory.getObject()); 
     super.afterPropertiesSet(); 
    } 

} 
+0

Dziękuję @Babl za odpowiedź. Zanim wypróbujesz proponowany kod, moje jedyne i ostatnie pytanie brzmi: Dlaczego to działało przed zmianą aplikacji na Spring Boot?Prior Spring Boot był już oparty na JavaConfig i Spring 4.1, a planowanie działało dobrze. – yglodt

+1

Jak już wspomniałem wcześniej, SpringBeanAutowiringSupport używa kontekstu aplikacji WWW do znajdowania ziaren i wprowadzania ich do obiektu, ale ponieważ aplikacja wiosennego rozruchu nie jest w pełni aplikacją internetową, kontekst jest pusty. Jeśli więc włączymy dzienniki dla SpringBeanAutowiringSupport na poziomie debugowania, pojawi się komunikat dewiacyjny informujący, że klasa docelowa nie została skonstruowana w aplikacji internetowej Spring. Wszelkie sposoby włączania sprężyny debugowania na wiosnę dadzą ci wiele wewnętrznych informacji na temat problemu;) – Babl

+0

Dzięki za szczegółowe wyjaśnienie! – yglodt

9

Moja odpowiedź nie do końca pasuje do ciebie pytanie, ale wiosna narażać inną umiejętność - aby uruchomić program do planowania oparty na wyrażeniach cron w dowolnej usłudze.

Korzystanie Spring.Boot Możesz skonfigurować aplikację do korzystania planującego przez proste umieszczanie

@EnableScheduling 
public class Application{ 
.... 

Potem wystarczy umieścić następującą adnotację na public metody @Service

@Service 
public class MyService{ 
... 
    @Scheduled(cron = "0 * * * * MON-FRI") 
    public void myScheduledMethod(){ 
    .... 
    } 
+2

Dziękuję, jestem tego świadomy i używam go już w Harmonogramach, które są statyczne. Problem, który opisałem powyżej, pochodzi z Harmonogramów, które mogą być ustawione przez użytkownika, więc muszę dodać/edytować/usunąć je w czasie wykonywania, co, o ile wiem, nie jest możliwe z adnotacją @Scheduled. – yglodt