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);