SpringBoot集成Quartz(解决@Autowired空指针Null问题即依赖注入的属性为null)
2017-11-15 17:02
2907 查看
使用spring-boot作为基础框架,其理念为零配置文件,所有的配置都是基于注解和暴露bean的方式。
Quartz的4个核心概念:
1、Job
表示一个工作,要执行的具体内容。此接口中只有一个方法
voidexecute(JobExecutionContextcontext)
2、JobDetail
JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。
3、Trigger代表一个调度参数的配置,什么时候去调。
4、Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。
集成Quartz的步骤如下:
1、POM中引入依赖
注意版本号
2、修改quartz.properties文件(可以存放在resources下,也可以存放未固定路径)
我们这里将使用基于DB的作业存储
注意:如果项目中同时运行了基于内存的任务调度(RAMJobStore)和基于数据库的任务调度(JobStoreTX)且属性文件中配置org.quartz.scheduler.instanceName=DefaultQuartzScheduler时,任务永远不会被写入到数据库,因为数据库的schedualer已被内存的schedualer覆盖
原因参考:
3、自定义JobFactory
首先解释一个常见的困境:Spring容器可以管理Bean,但是Quartz的job是自己管理的,如果在Job中注入Spring管理的Bean,需要先把Quartz的Job也让Spring管理起来,因此,我们需要重写JobFactory,详细的源码分析,请参考:
Quartz入门实例14-让Quartz的Job使用Spring注入的Bean
4、配置schedulerFactoryBean
Spring为了能集成Quartz,特意提供了管理Quartz的schedulerFactoryBean,必须配置,具体代码如下:
注意两点:
a、加载quartz.properties使用的是Spring的PropertiesFactoryBean,我将该文件存放在固定磁盘目录,因此使用了
newFileSystemResource(propertiesPath)
如果你的文件存放在resources下,请从classpath下加载:newClassPathResource("/quartz.properties")
b、我将quartz.properties路径配置在SpringBoot的yml中,因此使用了@ConfigurationProperties,不需要请移除,如果使用请注意get/set方法不能少
c、注意,一定要先执行propertiesFactoryBean.afterPropertiesSet();然后propertiesFactoryBean.getObject();
5、初始化DB
不解释,直接从quartz官网下载并初始化到你的DB中
6、编写定时任务
直接上代码:
7、单元测试或手工添加任务的Controller
单元测试不解释,如果使用了界面,编写的Controller如下
注意:
在controller层直接注入Scheduler即可,如下:
然后方法中直接调用
或者注入声明的
然后方法中先执行schedulerFactoryBean.getScheduler()获得scheduler
但是,一定要注意,千万不要自己直接去newStdSchedulerFactory(),默认的schedulerFactoryBean或注入的scheduler都是被StdScheduler,
创建的任务区别如下:
===================================华丽的分割线======================================
如果不需要让Spring管理quartz生成的job,则每个job作为普通的Bean对象,可以直接通过applicationContext对象直接getBean
代码如下
通过DB查询已添加的任务,查询SQL如下:
查询效果如图
参考:
如何获取SpringBoot项目的applicationContext对象
参考文章:
https://www.cnblogs.com/javanoob/p/springboot_schedule.htmlhttps://www.cnblogs.com/softidea/p/6073495.htmlhttp://blog.csdn.net/magic_best/article/details/50158125http://blog.csdn.net/iycynna_123/article/details/52993542http://www.jianshu.com/p/b460171c57ea
Quartz的4个核心概念:
1、Job
表示一个工作,要执行的具体内容。此接口中只有一个方法
voidexecute(JobExecutionContextcontext)
2、JobDetail
JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。
3、Trigger代表一个调度参数的配置,什么时候去调。
4、Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。
集成Quartz的步骤如下:
1、POM中引入依赖
<!--quartz--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>${quartz.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring-context-support.version}</version> </dependency>
注意版本号
<spring-context-support.version>4.1.6.RELEASE</spring-context-support.version> <quartz.version>2.2.3</quartz.version>
2、修改quartz.properties文件(可以存放在resources下,也可以存放未固定路径)
我们这里将使用基于DB的作业存储
#DefaultPropertiesfileforusebyStdSchedulerFactory #tocreateaQuartzSchedulerInstance,ifadifferent #propertiesfileisnotexplicitlyspecified. # #StdSchedulerFactory使用quartz.properties创建一个QuartzScheduler实例 #参数请参考:http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ # #Quartz提供两种基本作业存储类型 #--->第一种类型叫做RAMJobStore: #最佳的性能,因为内存中数据访问最快 #不足之处是缺乏数据的持久性,当程序路途停止或系统崩溃时,所有运行的信息都会丢失 #--->第二种类型叫做JDBC作业存储: #通过调整其quartz.properties属性文件,持久化任务调度信息 #使用数据库保存任务调度信息后,即使系统崩溃后重新启动,任务的调度信息将得到恢复 # #============================================================================ #基础配置 #============================================================================ #设置调度器的实例名(instanceName)和实例ID(instanceId) org.quartz.scheduler.instanceName:DefaultQuartzScheduler #如果使用集群,instanceId必须唯一,设置成AUTO org.quartz.scheduler.instanceId=AUTO org.quartz.scheduler.rmi.export:false org.quartz.scheduler.rmi.proxy:false org.quartz.scheduler.wrapJobExecutionInUserTransaction:false #============================================================================ #调度器线程池配置 #============================================================================ org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool #指定多少个工作者线程被创建用来处理Job org.quartz.threadPool.threadCount:10 #设置工作者线程的优先级(最大值10,最小值1,常用值5) org.quartz.threadPool.threadPriority:5 #加载任务代码的ClassLoader是否从外部继承 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true org.quartz.jobStore.misfireThreshold:60000 #============================================================================ #ConfigureJobStore作业存储配置 #============================================================================ #默认配置,数据保存到内存(调度程序信息是存储在被分配给JVM的内存里面,运行速度快) #org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore #持久化配置(存储方式使用JobStoreTX,也就是数据库) org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate #使用自己的配置文件 org.quartz.jobStore.useProperties:true #数据库中quartz表的表名前缀 org.quartz.jobStore.tablePrefix:qrtz_ org.quartz.jobStore.dataSource:qzDS #是否使用集群(如果项目只部署到一台服务器,就不用了) org.quartz.jobStore.isClustered=true #============================================================================ #ConfigureDatasources配置数据源 #============================================================================ org.quartz.dataSource.qzDS.driver:oracle.jdbc.OracleDriver org.quartz.dataSource.qzDS.URL:jdbc:oracle:thin:@10.132.81.134:1521:dsdb1 org.quartz.dataSource.qzDS.user:masmf org.quartz.dataSource.qzDS.password:masmf org.quartz.dataSource.qzDS.maxConnections:10
注意:如果项目中同时运行了基于内存的任务调度(RAMJobStore)和基于数据库的任务调度(JobStoreTX)且属性文件中配置org.quartz.scheduler.instanceName=DefaultQuartzScheduler时,任务永远不会被写入到数据库,因为数据库的schedualer已被内存的schedualer覆盖
原因参考:
QUARTZ任务不写入数据库分析
3、自定义JobFactory首先解释一个常见的困境:Spring容器可以管理Bean,但是Quartz的job是自己管理的,如果在Job中注入Spring管理的Bean,需要先把Quartz的Job也让Spring管理起来,因此,我们需要重写JobFactory,详细的源码分析,请参考:
Quartz与Spring集成Job如何自动注入Spring容器托管的对象
importorg.quartz.spi.TriggerFiredBundle; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.beans.factory.config.AutowireCapableBeanFactory; importorg.springframework.scheduling.quartz.AdaptableJobFactory; importorg.springframework.stereotype.Component; /** *Description:自定义JobFactory,使用Spring容器管理的Quartz的Bean(Job) *<p/> *AdaptableJobFactory是Spring提供的SchedulerFactoryBean的默认实例化工厂,将由直接实例化Job,没有被Spring管理 *User:lishaohua *Date:2017/11/1513:54 */ @Component publicclassMyJobFactoryextendsAdaptableJobFactory{ /** *AutowireCapableBeanFactory接口是BeanFactory的子类 *可以连接和填充那些生命周期不被Spring管理的已存在的bean实例 *具体请参考:http://blog.csdn.net/iycynna_123/article/details/52993542 */ @Autowired privateAutowireCapableBeanFactorycapableBeanFactory; /** *创建Job实例 * *@parambundle *@return *@throwsException */ @Override protectedObjectcreateJobInstance(TriggerFiredBundlebundle)throwsException{ //实例化对象 ObjectjobInstance=super.createJobInstance(bundle); //进行注入(Spring管理该Bean) capableBeanFactory.autowireBean(jobInstance); //返回对象 returnjobInstance; } }
4、配置schedulerFactoryBean
Spring为了能集成Quartz,特意提供了管理Quartz的schedulerFactoryBean,必须配置,具体代码如下:
importorg.quartz.ee.servlet.QuartzInitializerListener; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.beans.factory.config.PropertiesFactoryBean; importorg.springframework.boot.context.properties.ConfigurationProperties; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.core.io.FileSystemResource; importorg.springframework.scheduling.quartz.SchedulerFactoryBean; importjavax.sql.DataSource; importjava.io.IOException; importjava.util.Properties; /** *Description:Quartz调度配置 *<p/> *User:lishaohua *Date:2017/11/1410:27 */ @Configuration//类似xml中的<beans>标签,一般和@bean注解一起使用来配置一个Bean,让Spring来管理它的生命周期 @ConfigurationProperties(prefix="quartz.config")//把配置文件的信息自动装配到Bean上(以quartz.config前缀的) publicclassSchedulerConfig{ /** *配置文件路径 */ privateStringpropertiesPath;//quartz.config.propertiesPath @Autowired privateMyJobFactorymyJobFactory; /** *配置SchedulerFactoryBean * *@paramdataSource数据源 *@return *@throwsIOException */ @Bean//将一个方法产生为Bean并交给Spring容器管理(@Bean只能用在方法上) publicSchedulerFactoryBeanschedulerFactoryBean(DataSourcedataSource)throwsIOException{ //Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期 SchedulerFactoryBeanfactory=newSchedulerFactoryBean(); //启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 factory.setOverwriteExistingJobs(true); //延时启动(秒) factory.setStartupDelay(20); //设置quartz的配置文件 factory.setQuartzProperties(quartzProperties()); //设置自定义JobFactory,用于Spring管理Jobbean factory.setJobFactory(myJobFactory); returnfactory; } /** *加载Quartz配置 * *@return *@throwsIOException */ @Bean publicPropertiesquartzProperties()throwsIOException{ //使用Spring的PropertiesFactoryBean对属性配置文件进行管理 PropertiesFactoryBeanpropertiesFactoryBean=newPropertiesFactoryBean(); //注意:quartz的配置文件从指定系统目录中获取,而不是从classpath中获取 //propertiesFactoryBean.setLocation(newClassPathResource("/quartz.properties")); propertiesFactoryBean.setLocation(newFileSystemResource(propertiesPath));
//重要:保证其初始化 propertiesFactoryBean.afterPropertiesSet();
returnpropertiesFactoryBean.getObject(); } /** *初始化Quartz监听器,让Springboot启动时初始化Quartz *--web工程中,一般在web.xml中设置如下: *<listener> *<listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class> *</listener> *Quartz就会随着web容器启动,加载调度任务 * *@return */ @Bean publicQuartzInitializerListenerexecutorListener(){ returnnewQuartzInitializerListener(); } //========get/setmethod============================ publicStringgetPropertiesPath(){ returnpropertiesPath; } publicvoidsetPropertiesPath(StringpropertiesPath){ this.propertiesPath=propertiesPath; } }
注意两点:
a、加载quartz.properties使用的是Spring的PropertiesFactoryBean,我将该文件存放在固定磁盘目录,因此使用了
newFileSystemResource(propertiesPath)
如果你的文件存放在resources下,请从classpath下加载:newClassPathResource("/quartz.properties")
b、我将quartz.properties路径配置在SpringBoot的yml中,因此使用了@ConfigurationProperties,不需要请移除,如果使用请注意get/set方法不能少
c、注意,一定要先执行propertiesFactoryBean.afterPropertiesSet();然后propertiesFactoryBean.getObject();
5、初始化DB
不解释,直接从quartz官网下载并初始化到你的DB中
6、编写定时任务
直接上代码:
@Component publicclassUpdateCEBKeyJobextendsQuartzJobBean{ //日志记录 privatestaticLoggerlogger=LoggerFactory.getLogger(UpdateCEBKeyJob.class); //ECB密钥更新 @Autowired privateKeyOperationServicekeyOperationService; /** *执行Job * *@paramjobExecutionContext *@throwsJobExecutionException */ @Override protectedvoidexecuteInternal(JobExecutionContextjobExecutionContext)throwsJobExecutionException{ booleanupdateFlag=false; logger.info("-------------------updateECBkeyjobbegin:{}----------------", DateTimeUtil.getCurrentDateTime()); //===============01.正常执行任务====================== try{ /*KeyOperationServicekeyOperationService=ContextWrapper .getBean("keyOperationService",KeyOperationService.class);*/ updateFlag=keyOperationService.updateCEBKey(); }catch(Exceptione){ logger.error("更新光大密钥失败!",e); } //===============02.执行结果判定====================== if(!updateFlag){//如果更新失败,创建一次性任务再次执行(Job仍然是当前class) createJob(2); } logger.info("-------------------updateECBkeyjobend:{}----------------", DateTimeUtil.getCurrentDateTime()); }
7、单元测试或手工添加任务的Controller
单元测试不解释,如果使用了界面,编写的Controller如下
importcom.shengpay.mf.constant.ServerErrorEnum;
importcom.shengpay.mf.exception.ServerException;
importio.swagger.annotations.Api;
importio.swagger.annotations.ApiOperation;
importorg.quartz.*;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.scheduling.quartz.SchedulerFactoryBean;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.ResponseBody;
importjavax.servlet.http.HttpServletRequest;
importjava.util.HashMap;
importjava.util.Map;
/**
*Description:定时任务管理
*<p/>
*User:lishaohua
*Date:2017/11/1413:22
*/
@Controller
@Api("定时任务管理")//描述类的作用(Swagger注解)
publicclassJobController{
privatestaticLoggerlogger=LoggerFactory.getLogger(JobController.class);
/*@Autowired
privateSchedulerFactoryBeanschedulerFactoryBean;*/
@Autowired
privateSchedulerscheduler;
/**
*添加定时任务
*
*@paramrequest
*@paramjobClassName
*@paramjobGroupName
*@paramcronExpression
*@return
*/
@ApiOperation("添加定时任务")//描述方法的作用(Swagger注解)
@RequestMapping(value="/addJob",method={RequestMethod.POST})
@ResponseBody
publicMap<String,String>addJob(HttpServletRequestrequest,
@RequestParam(value="jobClassName")StringjobClassName,
@RequestParam(value="jobGroupName")StringjobGroupName,
@RequestParam(value="cronExpression")StringcronExpression){
Map<String,String>returnData=newHashMap<String,String>();
try{
/**
*构建JobDetail(表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容)
*/
JobDetailjobDetail=JobBuilder.newJob(getClass(jobClassName).getClass())//工作项1:Job类
.withIdentity(jobClassName,jobGroupName)//工作项2:job名以及所属组
.build();//构建
/**
*构建触发器Trigger(调度参数的配置,代表何时触发该任务)
*/
//通过cron表达式构建CronScheduleBuilder
CronScheduleBuilderscheduleBuilder=CronScheduleBuilder.cronSchedule(cronExpression);
//构建CronTrigger触发器
CronTriggertrigger=TriggerBuilder.newTrigger()
.withIdentity(jobClassName,jobGroupName)//工作项1:job名以及所属组
.withSchedule(scheduleBuilder)//工作项2:指定调度参数
.build();//构建
/**
*构建调度容器(当Trigger与JobDetail组合,就可以被Scheduler容器调度了)
*一个调度容器中可以注册多个JobDetail和Trigger。
*/
//获得调度容器
//Schedulerscheduler=getCurrentScheduler();
//注册调度任务
scheduler.scheduleJob(jobDetail,trigger);
//启动任务
scheduler.start();
returnData.put("msg","添加调度任务成功");
}catch(SchedulerExceptione){
logger.error("构建调度任务异常",e);
returnData.put("msg","添加调度任务异常:"+e.getMessage());
}catch(ServerExceptione){
logger.error("内部异常",e);
returnData.put("msg","添加调度任务异常:"+e.getMessage());
}catch(Exceptione){
logger.error("添加调度任务异常",e);
returnData.put("msg","添加调度任务异常:"+e.getMessage());
}
returnreturnData;
}
@ApiOperation("暂停定时任务")//描述方法的作用(Swagger注解)
@RequestMapping(value="/pauseJob",method={RequestMethod.POST})
@ResponseBody
publicMap<String,String>pauseJob(HttpServletRequestrequest,
@RequestParam(value="jobClassName")StringjobClassName,
@RequestParam(value="jobGroupName")StringjobGroupName){
Map<String,String>returnData=newHashMap<String,String>();
try{
//获得调度容器
//Schedulerscheduler=getCurrentScheduler();
//JobKey定义了job的名称和组别
JobKeyjobKey=JobKey.jobKey(jobClassName,jobGroupName);
//暂停任务
scheduler.pauseJob(jobKey);
returnData.put("msg","暂停调度任务成功");
}catch(SchedulerExceptione){
logger.error("暂停调度任务异常",e);
returnData.put("msg","暂停调度任务异常:"+e.getMessage());
}catch(Exceptione){
logger.error("暂停调度任务异常",e);
returnData.put("msg","暂停调度任务异常:"+e.getMessage());
}
returnreturnData;
}
@ApiOperation("继续定时任务")//描述方法的作用(Swagger注解)
@RequestMapping(value="/resumeJob",method={RequestMethod.POST})
@ResponseBody
publicMap<String,String>resumeJob(HttpServletRequestrequest,
@RequestParam(value="jobClassName")StringjobClassName,
@RequestParam(value="jobGroupName")StringjobGroupName){
Map<String,String>returnData=newHashMap<String,String>();
try{
//获得调度容器
//Schedulerscheduler=getCurrentScheduler();
//JobKey定义了job的名称和组别
JobKeyjobKey=JobKey.jobKey(jobClassName,jobGroupName);
//继续任务
scheduler.resumeJob(jobKey);
returnData.put("msg","继续调度任务成功");
}catch(SchedulerExceptione){
logger.error("继续调度任务异常",e);
returnData.put("msg","继续调度任务异常:"+e.getMessage());
}catch(Exceptione){
logger.error("继续调度任务异常",e);
returnData.put("msg","继续调度任务异常:"+e.getMessage());
}
returnreturnData;
}
/**
*更新定时任务:
*--传入的triggerKey有与之匹配的
*--旧触发器的触发时间没有完成
*
*@paramrequest
*@paramjobClassName
*@paramjobGroupName
*@paramcronExpression
*@return
*/
@ApiOperation("更新定时任务")//描述方法的作用(Swagger注解)
@RequestMapping(value="/rescheduleJob",method={RequestMethod.POST})
@ResponseBody
publicMap<String,String>rescheduleJob(HttpServletRequestrequest,
@RequestParam(value="jobClassName")StringjobClassName,
@RequestParam(value="jobGroupName")StringjobGroupName,
@RequestParam(value="cronExpression")StringcronExpression){
Map<String,String>returnData=newHashMap<String,String>();
try{
//获得调度容器
//Schedulerscheduler=getCurrentScheduler();
//构建旧的TriggerKey
TriggerKeytriggerKey=TriggerKey.triggerKey(jobClassName,jobGroupName);
//通过cron表达式构建CronScheduleBuilder
CronScheduleBuilderscheduleBuilder=CronScheduleBuilder.cronSchedule(cronExpression);
//从调度容器中获取旧的CronTrigger
CronTriggertrigger=(CronTrigger)scheduler.getTrigger(triggerKey);
//更新CronTrigger
trigger=trigger.getTriggerBuilder()
.withIdentity(triggerKey)//工作项1:job名以及所属组
.withSchedule(scheduleBuilder)//工作项2:指定调度参数
.build();//构建
//更新调度任务
scheduler.rescheduleJob(triggerKey,trigger);
returnData.put("msg","更新调度任务成功");
}catch(SchedulerExceptione){
logger.error("更新调度任务异常",e);
returnData.put("msg","更新调度任务异常:"+e.getMessage());
}catch(ServerExceptione){
logger.error("内部异常",e);
returnData.put("msg","更新调度任务异常:"+e.getMessage());
}catch(Exceptione){
logger.error("更新调度任务异常",e);
returnData.put("msg","更新调度任务异常:"+e.getMessage());
}
returnreturnData;
}
@ApiOperation("删除定时任务")//描述方法的作用(Swagger注解)
@RequestMapping(value="/removeJob",method={RequestMethod.POST})
@ResponseBody
publicMap<String,String>removeJob(HttpServletRequestrequest,
@RequestParam(value="jobClassName")StringjobClassName,
@RequestParam(value="jobGroupName")StringjobGroupName){
Map<String,String>returnData=newHashMap<String,String>();
try{
//获得调度容器
//Schedulerscheduler=getCurrentScheduler();
//TriggerKey定义了trigger的名称和组别
TriggerKeytriggerKey=TriggerKey.triggerKey(jobClassName,jobGroupName);
//暂停触发器
scheduler.resumeTrigger(triggerKey);
//暂停触发器
scheduler.unscheduleJob(triggerKey);
//移除任务
scheduler.deleteJob(JobKey.jobKey(jobClassName,jobGroupName));
returnData.put("msg","删除调度任务成功");
}catch(SchedulerExceptione){
logger.error("删除调度任务异常",e);
returnData.put("msg","删除调度任务异常:"+e.getMessage());
}catch(Exceptione){
logger.error("删除调度任务异常",e);
returnData.put("msg","删除调度任务异常:"+e.getMessage());
}
returnreturnData;
}
/**
*获得调度容器Scheduler
*
*@return
*@throwsSchedulerException
*/
/*privateSchedulergetCurrentScheduler()throwsSchedulerException{
//实例化Quartz默认的调度器工厂SchedulerFactory
//SchedulerFactorysf=newStdSchedulerFactory();
//获得调度容器
//Schedulersched=sf.getScheduler();
//returnsched;
//Schedulersched=schedulerFactoryBean.getScheduler();
//returnsched;
}*/
/**
*获得指定的类实例
*
*@paramclassname
*@return
*@throwsServerException
*/
privateJobgetClass(Stringclassname)throwsServerException{
JobbaseJob=null;
try{
//加载参数指定的类
Class<?>classTmp=Class.forName(classname);
//实例化
baseJob=(Job)classTmp.newInstance();
}catch(ClassNotFoundExceptione){
logger.error("找不到指定的类",e);
thrownewServerException(ServerErrorEnum.INTERNAL_ERROR);
}catch(InstantiationExceptione){
logger.error("实例化类失败",e);
thrownewServerException(ServerErrorEnum.INTERNAL_ERROR);
}catch(IllegalAccessExceptione){
logger.error("实例化类失败",e);
thrownewServerException(ServerErrorEnum.INTERNAL_ERROR);
}
returnbaseJob;
}
}
注意:
在controller层直接注入Scheduler即可,如下:
@Autowired
privateSchedulerscheduler;
然后方法中直接调用
//注册调度任务
scheduler.scheduleJob(jobDetail,trigger);
//启动任务
scheduler.start();
或者注入声明的
@Autowired
privateSchedulerFactoryBeanschedulerFactoryBean;
然后方法中先执行schedulerFactoryBean.getScheduler()获得scheduler
//获得调度容器
Schedulerscheduler=schedulerFactoryBean.getScheduler();
//注册调度任务
scheduler.scheduleJob(jobDetail,trigger);
//启动任务
scheduler.start();
但是,一定要注意,千万不要自己直接去newStdSchedulerFactory(),默认的schedulerFactoryBean或注入的scheduler都是被StdScheduler,
newStdSchedulerFactory()获得的Scheduler将无法被Spring管理,如下代码:
//实例化Quartz默认的调度器工厂SchedulerFactory
SchedulerFactorysf=newStdSchedulerFactory();
//获得调度容器
Schedulersched=sf.getScheduler();
创建的任务区别如下:
===================================华丽的分割线======================================
如果不需要让Spring管理quartz生成的job,则每个job作为普通的Bean对象,可以直接通过applicationContext对象直接getBean
代码如下
importorg.springframework.beans.BeansException;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.ApplicationContextAware;
importorg.springframework.stereotype.Component;
/**
*Description:applicationContext工具类
*<p/>
*User:lishaohua
*Date:2017/11/1613:48
*/
@Component
publicclassApplicationContextUtilimplementsApplicationContextAware{
/**
*上下文对象实例
*/
privatestaticApplicationContextappContext;
/**
*Spring自动注入applicationContext对象
*--因此该Bean必须@Component被Springscan发现
*
*@paramapplicationContext
*@throwsBeansException
*/
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{
appContext=applicationContext;
}
/**
*获得applicationContext
*@return
*/
publicstaticApplicationContextgetAppContext(){
returnappContext;
}
/**
*根据name获取Bean
*
*@paramname
*@return
*/
publicstaticObjectgetBean(Stringname){
returngetAppContext().getBean(name);
}
/**
*根据class获取Bean
*
*@paramclazz
*@param<T>
*@return
*/
publicstatic<T>TgetBean(Class<T>clazz){
returngetAppContext().getBean(clazz);
}
/**
*根据name、class获得Bean
*
*@paramname
*@paramclazz
*@param<T>
*@return
*/
publicstatic<T>TgetBean(Stringname,Class<T>clazz){
returngetAppContext().getBean(name,clazz);
}
}
通过DB查询已添加的任务,查询SQL如下:
selectTO_CHAR(t.next_fire_time/(1000*60*60*24)+
TO_DATE('1970-01-0108:00:00','YYYY-MM-DDHH24:MI:SS'),'YYYY-MM-DDHH24:MI:SS')next_fire_datetime,
t.*
fromqrtz_triggerst;
查询效果如图
参考:
参考文章:
相关文章推荐
- activiti解决实现ExecutionListener spring 自动注入@Autowired为null问题
- spring@Autowired注入为null的问题,2017年9月14日21点41分记录
- 解决 SpringMvc 非controller类使用@Autowired注解 service注入为null的问题
- 【SpringBoot】拦截器使用@Autowired注入接口为null解决方法
- 解决非controller使用@Autowired注解注入为null问题
- JAVA解决在@autowired,@Resource注入为null的问题
- 解决非controller使用@Autowired注解注入为null问题
- mapper注入失败问题解决 {@org.springframework.beans.factory.annotation.Autowired(required=true)}
- spring 在Thread中注入@Resource@Autowired失败,总为null~解决
- Spring使用@Resource、@Autowired注入时出现空指针问题的原因
- 如何解决SpringBoot JpaRepository @Autowired 没法自动注入的问题
- 因Spring AOP导致@Autowired依赖注入失败的解决方法
- 【SpringBoot】拦截器使用@Autowired注入接口为null解决方法
- 解决Springboot @Autowired 无法注入问题
- Spring使用@Resource、@Autowired注入时出现空指针问题的原因
- 对于Spring对websocket的属性注入失败问题,困扰我一天,最后终于解决了
- 利用Lombok编写优雅的spring依赖注入代码,去掉繁人的@Autowired
- spring下应用@Resource, @Autowired 和 @Inject注解进行依赖注入的差异
- 关于 Spring 中 Autowired 注入接口的几个问题
- spring下应用@Resource, @Autowired 和 @Inject注解进行依赖注入的差异