I have the QuartzConfig configuration class that have three beans ,How can I call this beans in spring mvc controller method.
This beans executed automatically once I start application,But I don't want that I want to execute this beans by controller
Quartz configuration class
#Configuration
public class QuartzConfig {
#Autowired
private PlatformTransactionManager transactionManager;
#Autowired
private ApplicationContext applicationContext;
#Bean
public SchedulerFactoryBean quartzScheduler() {
SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
quartzScheduler.setTransactionManager(transactionManager);
quartzScheduler.setOverwriteExistingJobs(true);
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
quartzScheduler.setJobFactory(jobFactory);
Trigger[] triggers = {
processMyJobTrigger().getObject()
};
quartzScheduler.setTriggers(triggers);
return quartzScheduler;
}
#Bean
public JobDetailFactoryBean processMyJob() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(HelloJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
#Bean
public CronTriggerFactoryBean processMyJobTrigger() {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(processMyJob().getObject());
cronTriggerFactoryBean.setCronExpression("0 0/1 * * * ?");
return cronTriggerFactoryBean;
}
}
Quartz job
#Service
#Transactional
public class HelloJob implements Job{
#Inject
TestrecordRepository testrecordRepository;
#Inject
ScoreRepository scoreRepository;
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Quartz!");
List<Testrecord> records=testrecordRepository.findAll();
for(Testrecord t:records){
Testrecord testrecord = new Testrecord();
testrecord.setValue_integer(t.getValue_integer());
testrecord.setId(t.getId());
RuleExecutor ruleExecutor = new RuleExecutor();
Score score= ruleExecutor.processRules(testrecord);
scoreRepository.save(score);
}
}
}
Related
I am integrating Quartz with Spring boot and postgres.
I have created all the required tables for quartz.
Issue : The application starts but the Job is not getting executed as per the cron.
I want that the jobs should be automatically scheduled on start-up and should run as per the cron expression.
But right now the application starts and no trigger is fired.
The QuartzJobFactory class
public class QuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
#Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
The ConfigQuartz class
#Configuration
public class ConfigQuartz {
#Value("${quartz.dataSource.myDS.URL}")
String orgQuartzDatasourceMydsUrl;
#Value("${spring.datasource.username}")
String orgQuartzDatasourceMydsUser;
#Value("${spring.datasource.password}")
String orgQuartzDatasourceMydsPassword;
#Value("${quartz.enabled}")
Boolean isQuartzEnabled;
private static List<Trigger> triggers = new ArrayList<>();
#Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
QuartzJobFactory sampleJobFactory = new QuartzJobFactory();
sampleJobFactory.setApplicationContext(applicationContext);
return sampleJobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory)
throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(isQuartzEnabled);
// factory.setDataSource(dataSource);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
return factory;
}
public Properties setQuartzProperties() {
Properties properties = new Properties();
properties.setProperty("org.quartz.dataSource.myDS.URL",orgQuartzDatasourceMydsUrl);
properties.setProperty("org.quartz.dataSource.myDS.user",orgQuartzDatasourceMydsUser);
properties.setProperty("org.quartz.dataSource.myDS.password",orgQuartzDatasourceMydsPassword);
return properties;
}
#Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
propertiesFactoryBean.setProperties(setQuartzProperties());
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
public static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs,
String triggerName) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(0L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
factoryBean.setName(triggerName);
// in case of misfire, ignore all missed triggers and continue :
factoryBean.setMisfireInstruction(
SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
return factoryBean;
}
// Use this method for creating cron triggers instead of simple triggers:
public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression,
String triggerName) throws Exception {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setCronExpression(cronExpression);
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
factoryBean.setName(triggerName);
try {
factoryBean.afterPropertiesSet();
} catch (ParseException e) {
throw new Exception(e.getMessage());
}
triggers.add(factoryBean.getObject());
return factoryBean;
}
public static JobDetailFactoryBean createJobDetail(Class jobClass) {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
// job has to be durable to be stored in DB:
factoryBean.setDurability(true);
return factoryBean;
}
}
The QuartzJobFactory class
public class QuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
#Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
The CronExpression class
public class CronExpression {
private static final Map<String, String> cronExpressionMap = ImmutableMap
.<String, String>builder()
.put(TestJob.CLASS_NAME, "* 0 0 ? * * *")
.build();
public static String get(String key) {
return cronExpressionMap.get(key);
}
}
The TestJob class
#Component
#DisallowConcurrentExecution
public class TestJob implements Job {
public static final String CLASS_NAME = "TestJob";
private final String JOB_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_JOB_SUFFIX;
private final String TRIGGER_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_TRIGGER_SUFFIX;
#Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
LocalDateTime start = LocalDateTime.now();
System.out.println("*************** execute method is running *******");
}
#Bean(name = JOB_BEAN_NAME)
public JobDetailFactoryBean sampleJob() {
return ConfigQuartz.createJobDetail(this.getClass());
}
#Bean(name = TRIGGER_BEAN_NAME)
public CronTriggerFactoryBean sampleJobTrigger(
#Qualifier(JOB_BEAN_NAME) JobDetailFactoryBean jobDetail) throws Exception {
return ConfigQuartz.createCronTrigger(jobDetail.getObject(), CronExpression.get(CLASS_NAME),
CLASS_NAME);
}
}
The main class
EnableConfigurationProperties
#EntityScan(basePackages = {"com.example"})
#ComponentScan({"com.example"})
#SpringBootApplication
#EnableScheduling
public class QuartzSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzSchedulerApplication.class, args);
}
}
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/quartz
spring.datasource.username=postgres
spring.datasource.password=mysecretpassword
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.show-sql=true
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.driverClassName=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=none
spring.datasource.hikari.maximum-pool-size=5
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
quartz.dataSource.myDS.URL=jdbc:postgresql://localhost:5432/quartz
quartz.enabled=true
The quartz.properties
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = PropScheduler
org.quartz.scheduler.instanceId = 10
#org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 5000
org.quartz.scheduler.name=test-schedulers
#============================================================================
# Configure Datasources
#============================================================================
org.quartz.dataSource.myDS.driver=org.postgresql.Driver
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery = select 1
#============================================================================
# Configure trigger history loging , enble if needed more information regaring triggers
#============================================================================
#org.quartz.plugin.triggerHistory.class=org.quartz.plugins.history.LoggingTriggerHistoryPlugin
#org.quartz.plugin.triggerHistory.triggerFiredMessage=Trigger [{1}.{0}] fired job [{6}.{5}] scheduled at: {2, date, dd-MM-yyyy HH:mm:ss.SSS}, next scheduled at: {3, date, dd-MM-yyyy HH:mm:ss.SSS}
#org.quartz.plugin.triggerHistory.triggerCompleteMessage=Trigger [{1}.{0}] completed firing job [{6}.{5}] with resulting trigger instruction code: {9}. Next scheduled at: {3, date, dd-MM-yyyy HH:mm:ss.SSS}
#org.quartz.plugin.triggerHistory.triggerMisfiredMessage=Trigger [{1}.{0}] misfired job [{6}.{5}]. Should have fired at: {3, date, dd-MM-yyyy HH:mm:ss.SSS}
Your TriggerListener class (SimpleTriggerFactoryBean) doesn't seem to be implementing TriggerListener interface of quartz.
You can create custom class which implements TriggerListener and see if that works.
Reference
I need to start spring batch job in Async method, but I got lazy exception in item processor:
This is my Approach:
Service that contains Async method looks like:
#Service
#RequiredArgsConstructor
#Slf4j
public class BatchService {
#Qualifier(value = "attachmentsJob")
private final Job job;
#Qualifier(value = "asyncJobLauncher")
private final JobLauncher jobLauncher;
private final JobLogService jobLogService;
#Async
public void migrateAttachments() {
JobLogDB jobLogDB = jobLogService.createStartJobLog(job);
try {
Map<String, JobParameter> parameters = new HashMap<>();
parameters.put("jobId", new JobParameter(jobLogDB.getId()));
jobLauncher.run(job, new JobParameters(parameters));
} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException | JobParametersInvalidException e) {
e.printStackTrace();
jobLogService.markJobAsFailed(jobLogDB.getId());
}
}
}
The Batch Config is:
#Configuration
#RequiredArgsConstructor
#EnableBatchProcessing
public class BatchConfig {
private final JobBuilderFactory jobBuilderFactory;
private final JobRepository jobRepository;
private final StepBuilderFactory stepBuilderFactory;
private final MessageRepository messageRepository;
private final PlatformTransactionManager platformTransactionManager;
private final MessageDbAttachmentsProcessor messageDbAttachmentsProcessor;
#Bean(name = "asyncBatchTaskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(64);
executor.setMaxPoolSize(64);
executor.setQueueCapacity(64);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("MigrateAttachmentsThread-");
executor.initialize();
return executor;
}
/**
* Batch Reader
*/
#Bean
public RepositoryItemReader<MessageDB> reader() {
return new RepositoryItemReaderBuilder<MessageDB>().name("readerName")
.repository(messageRepository)
.methodName("findAllByTaskIdIsNotNull")
.pageSize(10)
.sorts(Collections.singletonMap("taskId", Sort.Direction.ASC))
.build();
}
/**
* Batch Processor
*/
#Bean
public AsyncItemProcessor<MessageDB, MessageDB> processor() {
AsyncItemProcessor<MessageDB, MessageDB> asyncItemProcessor = new AsyncItemProcessor<>();
asyncItemProcessor.setDelegate(messageDbAttachmentsProcessor);
asyncItemProcessor.setTaskExecutor(taskExecutor());
return asyncItemProcessor;
}
/**
* Batch Writer
*/
#Bean
public RepositoryItemWriter<MessageDB> writer() {
RepositoryItemWriter repositoryItemWriter = new RepositoryItemWriter();
repositoryItemWriter.setRepository(messageRepository);
repositoryItemWriter.setMethodName("save");
return repositoryItemWriter;
}
#Bean
public AsyncItemWriter<MessageDB> asyncWriter() {
AsyncItemWriter<MessageDB> asyncItemWriter = new AsyncItemWriter<>();
asyncItemWriter.setDelegate(writer());
return asyncItemWriter;
}
#Bean(name = "attachmentsJob")
public Job migrateTaskAttachmentsJob(JobCompletionNotificationListener listener, Step step) {
return jobBuilderFactory.get("taskAttachmentsJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step)
.end()
.build();
}
#Bean
public Step step() {
return stepBuilderFactory.get("step")
.<MessageDB, Future<MessageDB>>chunk(5)
.reader(reader())
.processor(processor())
.writer(asyncWriter())
.transactionManager(platformTransactionManager)
.build();
}
#Bean(name = "asyncJobLauncher")
public JobLauncher asyncJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.setTaskExecutor(taskExecutor());
return jobLauncher;
}
}
When I call the method in the MessageDbAttachmentsProcessor I get lazy exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx.xxx.xxx.xxx, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.write(AbstractPersistentCollection.java:409)
at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:407)
I tried to fix it by adding #Transactional(propagation = Propagation.REQUIRES_NEW) on migrateAttachments method but without success, after I added I got following exception:
java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove #Transactional annotations from client).
I do not know what to change and in which direction to modify. Any help is welcomed.
I've tried the following methods to use the scheduler, but I can't find an answer, so I'd like to ask you a question.
The scheduler service is running exactly on time.
However, only 'sessionService.getUserInfo()' runs.
We are not doing any work on youtubeSearchService.searchYoutube and youtubeSearchService.searchYoutube.
Why there's only work one service. I wonder what to do to use multiple services.
#Component
public class SchedulerService {
private static final Logger logger = LoggerFactory.getLogger(SchedulerService.class);
#Autowired
private YoutubeSearchService youtubeSearchService;
#Autowired
private WeatherService weatherService;
#Autowired
private SessionService sessionService;
public static int i = 0;
public static int j = 0;
#Scheduled(cron="0 40 0/1 * * *")
public void weatherSchedulerService() throws Exception {
++i;
weatherService.insertRTweather(sessionService.getUserInfo());
}
#Scheduled(cron = "0 0/1 * * * *")
public void youtubeSearchSchedulerService() throws Exception {
++j;
youtubeSearchService.searchYoutube(sessionService.getUserInfo(),j);
}
}
I used to have challenges with spring scheduler, especially with annotation based config and finally use following solution I hope it helps:
SchedulerConfig.java using quartz
#Configuration
public class SchedulerConfig
{
private static final Logger logger = Logger.getLogger(SchedulerConfig.class.getName());
#Autowired
private ApplicationContext applicationContext;
#Bean
public SpringBeanJobFactory springBeanJobFactory()
{
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
logger.info("Configuring Job factory");
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job)
{
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
logger.info("Setting the Scheduler up");
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
return schedulerFactory;
}
#Bean
public JobDetailFactoryBean jobDetail()
{
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(SchedulerService.class);
jobDetailFactory.setName("Qrtz_Job_Detail");
jobDetailFactory.setDescription("Invoke Sample Job service...");
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
#Bean
public CronTriggerFactoryBean trigger(JobDetail job)
{
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
//three am
trigger.setCronExpression("0 0 3 * * ?");
trigger.setJobDetail(job);
trigger.setName("Qrtz_Trigger");
return trigger;
}
}
quartz.properties : put it in classptah
# thread-pool
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=1
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
# job-store
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
# others
org.quartz.jobStore.misfireThreshold = 60000
Your scheduler service define as follow :
#Component
public class SchedulerService implements Job {
#Autowired
private YoutubeSearchService youtubeSearchService;
#Autowired
private WeatherService weatherService;
#Autowired
private SessionService sessionService;
public void execute(JobExecutionContext context) throws JobExecutionException
{
weatherService.insertRTweather(sessionService.getUserInfo());
}
}
if you want two define more than one schedule, you can it to schedulerconfig by adding a jobdetail and trigger.
Don't forget to add quartz jar file
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
</dependency>
I have implemented Spring Quartz scheduler example using this link
I am having simple MyJobTwo.java component that has a method executeInternal() that is being called using CronTriggerFactoryBean.
This is my QuartzConfiguration.java
#Configuration
#ComponentScan("com.example")
public class QuartzConfiguration {
// we need to create a bean that will excuted by MethodInvokingJobDetailFactoryBean
// in this case we have myJobOne is the simple bean
#Bean
public MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean obj = new MethodInvokingJobDetailFactoryBean();
obj.setTargetBeanName("myJobOne");
obj.setTargetMethod("myTask");
return obj;
}
// This trigger will schedule the job after 3 seconds and repeat after every 30 seconds for 3+1 times.
#Bean
public SimpleTriggerFactoryBean simpleTriggerFactoryBean(){
SimpleTriggerFactoryBean stFactory = new SimpleTriggerFactoryBean();
stFactory.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
stFactory.setStartDelay(3000);
stFactory.setRepeatInterval(30000);
stFactory.setRepeatCount(1);
return stFactory;
}
// We use it to configure complex job such as job scheduling using cron-expression
#Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(MyJobTwo.class);
// Map<String,Object> map = new HashMap<String,Object>();
// map.put("myJobOne", myJobOne);
// map.put(MyJobTwo.myJodOne, 1);
//factory.setJobDataAsMap(map);
//factory.setGroup("mygroup");
//factory.setName("myjob");
return factory;
}
// CronTriggerFactoryBean configures JobDetailFactoryBean
// We also configure start delay, trigger name, and cron-expression to schedule the job
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(){
CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
stFactory.setJobDetail(jobDetailFactoryBean().getObject());
stFactory.setStartDelay(3000);
//stFactory.setName("mytrigger");
//stFactory.setGroup("mygroup");
stFactory.setCronExpression("0 0/1 * 1/1 * ? *");
return stFactory;
}
// SchedulerFactoryBean use to register the triggers
// those registered triggers will be executed
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(cronTriggerFactoryBean().getObject());
//scheduler.setTriggers(simpleTriggerFactoryBean().getObject());
return scheduler;
}
}
This is the bean that I am executing using CronTriggerFactoryBean.
MyJobTwo.java
#Component
public class MyJobTwo extends QuartzJobBean {
private SmtpMailSender smtpMailSender;
#Autowired
public MyJobTwo(MyJobOne myJobOne, SmtpMailSender smtpMailSender) {
super();
this.myJobOne = myJobOne;
this.smtpMailSender = smtpMailSender;
}
#Override
protected void executeInternal(JobExecutionContext ctx)
throws JobExecutionException {
System.out.println("this is the test");
myJobOne.myTask();
System.out.println("task is done");
}
}
Whenever I am trying to inject other beans and service I am getting these errors. Anyone having any idea what is causing these errors, what changes do I need to make?
org.quartz.SchedulerException: Job instantiation failed
at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:45)
at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:375)
Caused by: java.lang.InstantiationException: com.example.job.MyJobTwo
at java.lang.Class.newInstance(Class.java:427)
at org.springframework.scheduling.quartz.AdaptableJobFactory.createJobInstance(AdaptableJobFactory.java:58)
at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:41)
... 2 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.example.job.MyJobTwo.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 4 common frames omitted
The default job factory implementation AdaptableJobFactory doesn't have autowiring capability.
To use dependency injection do following:
1.Create job factory
package com.concretepage.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
#Override
public Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job); //the magic is done here
return job;
}
}
Implementation is found on http://codrspace.com/Khovansa/spring-quartz-with-a-database/
2.Update schedulerFactoryBean declaration in QuartzConfiguration:
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(simpleTriggerFactoryBean().getObject(), cronTriggerFactoryBean().getObject());
scheduler.setJobFactory(jobFactory());
return scheduler;
}
#Bean
public JobFactory jobFactory() {
return new AutowiringSpringBeanJobFactory();
}
Use setter-based injection instead of constructor injection
I use the following configuration class to integrate spring framework with Quartz,It works fine,but the job fires dynamically once the application has started because I use #Configuration annotation,I want to fire the job manually by controller and ui.
How to Fire Quartz manually By Spring controller?
Quartz configuration class
#Configuration
public class QuartzConfig {
#Autowired
private PlatformTransactionManager transactionManager;
#Autowired
private ApplicationContext applicationContext;
#Bean
public SchedulerFactoryBean quartzScheduler() {
SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
quartzScheduler.setTransactionManager(transactionManager);
quartzScheduler.setOverwriteExistingJobs(true);
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
quartzScheduler.setJobFactory(jobFactory);
Trigger[] triggers = {
processMyJobTrigger().getObject()
};
quartzScheduler.setTriggers(triggers);
return quartzScheduler;
}
#Bean
public JobDetailFactoryBean processMyJob() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(HelloJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
#Bean
public CronTriggerFactoryBean processMyJobTrigger() {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(processMyJob().getObject());
cronTriggerFactoryBean.setCronExpression("0 0/1 * * * ?");
return cronTriggerFactoryBean;
}
}
Quartz job
#Service
#Transactional
public class HelloJob implements Job{
#Inject
TestrecordRepository testrecordRepository;
#Inject
ScoreRepository scoreRepository;
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello Quartz!");
List<Testrecord> records=testrecordRepository.findAll();
for(Testrecord t:records){
Testrecord testrecord = new Testrecord();
testrecord.setValue_integer(t.getValue_integer());
testrecord.setId(t.getId());
RuleExecutor ruleExecutor = new RuleExecutor();
Score score= ruleExecutor.processRules(testrecord);
scoreRepository.save(score);
}
}
}
From the controller you need to get access to SchedulerFactoryBean, then take scheduler and trigger job you like.
Scheduler scheduler = (Scheduler) getApplicationContext().getBean("schedulerFactoryBean");
scheduler.triggerJob(JobKey jobKey)