I'm using spring boot and I have a service which stores/retrieves some data from DB. I want to use a quartz job which uses my service. I tried many suggestions from the internet to integrate quartz with spring boot, but it doesn't work. Can you help me pls?
Here is my code:
1) I added org.quartz-scheduler as dependency in pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
</dependencies>
2) This is my application.properties configured to use mysql as DB for my service:
server.port=8281 spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=myusername spring.datasource.password=mypassword
3) This is my service:
@Service public class ReportService { JdbcTemplate jdbcTemplate; public ReportService(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public List getPendingReports() { String sql = "SELECT * FROM report WHERE status = '" + ReportStatus.PENDING.name() +"'"; ReportMapper reportsMapper = new ReportMapper(); List reports = jdbcTemplate.query(sql, reportsMapper); return reports; } }
4) The scheduler class:
import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.SimpleScheduleBuilder; import org.quartz.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; public class ReportScheduler { public void scanAndUpdateReports() { SchedulerFactory sf = new StdSchedulerFactory(); try { Scheduler scheduler = sf.getScheduler(); scheduler.start(); JobDetail job = JobBuilder.newJob(ReportsJob.class) .withIdentity("reportsJob") .build(); SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity("reportsTrigger") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(60).repeatForever()) .build(); scheduler.scheduleJob(job, trigger); } catch (SchedulerException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
5) And my job class where I want to autowire the ReportService, but it is null:
public class ReportsJob implements Job { @Autowired ReportService reportService; //this doesn't work (it is null) @Override public void execute(JobExecutionContext context) throws JobExecutionException { List reports = reportService.getPendingReports(); System.out.println("Reports:\n"+reports); } }
6) Right now I'm calling the scheduler from main method:
@SpringBootApplication public class ReportAppBeApplication { public static void main(String[] args) { SpringApplication.run(ReportAppBeApplication.class, args); ReportScheduler rs = new ReportScheduler(); rs.scanAndUpdateReports(); } }
It is null because @Autowired
only works in a @Component
, @Repository
or @Service
annotated class. Annotate your ReportJob
class and make sure the map where you store the class is included in the component scan
on startup. You can include the map for scanning with:
@ComponentScan(basePackages={"folderOfReportJob"})
This annotation should be added to an @Configuration
or @SpringBootApplication
annotated class.
EDIT:
If you don't want to make your job a component you can also get the bean manually through the ApplicationContext
class. It goes like this:
private static ApplicationContext ac;
ReportService reportService = ac.getBean(ReportService.class);
I happened to find you a chinese blog writtig about a functioning implementation. may i say you're trying to implement something like spring-boot-starter-quartz
.
To Summary, you should defined your own QuartzJobFactory
as to modify createJobInstance
method adding autowireBean
to newly create JobDetail instance.
something like,
JobDetail job = JobBuilder.newJob(ReportsJob.class)
.withIdentity("reportsJob")
.build();
// Pseudocode here
autowiredBean(job);
working example,
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法,把Job注入到spring中
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
@Configuration
class Configuration {
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler = factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}
full post here: https://www.cnblogs.com/supiaopiao/p/14953978.html
In my case, I added annotation @DisallowConcurrentExecution. After that I able to access autowired services, smoothly.
import org.quartz.DisallowConcurrentExecution;
@DisallowConcurrentExecution
public class InvoiceJob implements Job {
@Autowired
private RuntimeConfigurationService runtimeConfigurationService;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.