• SpringBoot集成Quartz(解决@Autowired空指针Null问题即依赖注入的属性为null)


    使用spring-boot作为基础框架,其理念为零配置文件,所有的配置都是基于注解和暴露bean的方式。

    Quartz的4个核心概念:

    1、Job
    表示一个工作,要执行的具体内容。此接口中只有一个方法
    void execute(JobExecutionContext context)

    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的作业存储

    # Default Properties file for use by StdSchedulerFactory
    # to create a Quartz Scheduler Instance, if a different
    # properties file is not explicitly specified.
    #
    # StdSchedulerFactory使用quartz.properties 创建一个Quartz Scheduler实例
    # 参数请参考: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
    
    #============================================================================
    # Configure JobStore 作业存储配置
    #============================================================================
    
    # 默认配置,数据保存到内存(调度程序信息是存储在被分配给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
    
    #============================================================================
    # Configure Datasources 配置数据源
    #============================================================================
    
    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容器托管的对象

    Quartz入门实例14-让Quartz的Job使用Spring注入的Bean

    import org.quartz.spi.TriggerFiredBundle;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
    import org.springframework.scheduling.quartz.AdaptableJobFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * Description: 自定义JobFactory,使用Spring容器管理的Quartz的Bean(Job)
     * <p/>
     * AdaptableJobFactory是Spring提供的SchedulerFactoryBean的默认实例化工厂,将由直接实例化Job,没有被Spring管理
     * User: lishaohua
     * Date: 2017/11/15  13:54
     */
    @Component
    public class MyJobFactory extends AdaptableJobFactory {
    
        /**
         * AutowireCapableBeanFactory接口是BeanFactory的子类
         * 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例
         * 具体请参考:http://blog.csdn.net/iycynna_123/article/details/52993542
         */
        @Autowired
        private AutowireCapableBeanFactory capableBeanFactory;
    
        /**
         * 创建Job实例
         *
         * @param bundle
         * @return
         * @throws Exception
         */
        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            // 实例化对象
            Object jobInstance = super.createJobInstance(bundle);
            // 进行注入(Spring管理该Bean)
            capableBeanFactory.autowireBean(jobInstance);
            //返回对象
            return jobInstance;
        }
    }

    4、配置schedulerFactoryBean

    Spring为了能集成Quartz,特意提供了管理Quartz的schedulerFactoryBean,必须配置,具体代码如下:

    import org.quartz.ee.servlet.QuartzInitializerListener;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.config.PropertiesFactoryBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.util.Properties;
    
    /**
     * Description: Quartz调度配置
     * <p/>
     * User: lishaohua
     * Date: 2017/11/14  10:27
     */
    @Configuration //类似xml中的<beans>标签,一般和@bean注解一起使用来配置一个Bean,让Spring来管理它的生命周期
    @ConfigurationProperties(prefix = "quartz.config")//把配置文件的信息自动装配到Bean上(以quartz.config前缀的)
    public class SchedulerConfig {
        /**
         * 配置文件路径
         */
        private String propertiesPath;//quartz.config.propertiesPath
    
        @Autowired
        private MyJobFactory myJobFactory;
    
        /**
         * 配置SchedulerFactoryBean
         *
         * @param dataSource 数据源
         * @return
         * @throws IOException
         */
        @Bean //将一个方法产生为Bean并交给Spring容器管理(@Bean只能用在方法上)
        public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
            //Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期
            SchedulerFactoryBean factory = new SchedulerFactoryBean();
            //启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
            factory.setOverwriteExistingJobs(true);
            // 延时启动(秒)
            factory.setStartupDelay(20);
            //设置quartz的配置文件
            factory.setQuartzProperties(quartzProperties());
            //设置自定义Job Factory,用于Spring管理Job bean
            factory.setJobFactory(myJobFactory);
            return factory;
        }
    
        /**
         * 加载Quartz配置
         *
         * @return
         * @throws IOException
         */
        @Bean
        public Properties quartzProperties() throws IOException {
            //使用Spring的PropertiesFactoryBean对属性配置文件进行管理
            PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
            //注意:quartz的配置文件从指定系统目录中获取,而不是从classpath中获取
            //propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
            propertiesFactoryBean.setLocation(new FileSystemResource(propertiesPath));
            //重要:保证其初始化
            propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
        }
    
        /**
         * 初始化Quartz监听器,让Spring boot启动时初始化Quartz
         * --web工程中,一般在web.xml中设置如下:
         * <listener>
         * <listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>
         * </listener>
         * Quartz就会随着web容器启动,加载调度任务
         *
         * @return
         */
        @Bean
        public QuartzInitializerListener executorListener() {
            return new QuartzInitializerListener();
        }
    
        //========get/set method============================
        public String getPropertiesPath() {
            return propertiesPath;
        }
    
        public void setPropertiesPath(String propertiesPath) {
            this.propertiesPath = propertiesPath;
        }
    }

    注意两点:

    a、加载quartz.properties使用的是Spring的PropertiesFactoryBean,我将该文件存放在固定磁盘目录,因此使用了

    new FileSystemResource(propertiesPath)

    如果你的文件存放在resources下,请从classpath下加载:new ClassPathResource("/quartz.properties")

    b、我将quartz.properties路径配置在SpringBoot的yml中,因此使用了@ConfigurationProperties,不需要请移除,如果使用请注意get/set方法不能少

    c、注意,一定要先执行propertiesFactoryBean.afterPropertiesSet();然后propertiesFactoryBean.getObject();

    5、初始化DB

    不解释,直接从quartz官网下载并初始化到你的DB中

    6、编写定时任务

    直接上代码:

    @Component
    public class UpdateCEBKeyJob extends QuartzJobBean {
        //日志记录
        private static Logger logger = LoggerFactory.getLogger(UpdateCEBKeyJob.class);
    
        //ECB密钥更新
        @Autowired
        private KeyOperationService keyOperationService;
    
    
        /**
         * 执行Job
         *
         * @param jobExecutionContext
         * @throws JobExecutionException
         */
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            boolean updateFlag = false;
            logger.info("-------------------update ECB key job begin:{} ----------------",
                    DateTimeUtil.getCurrentDateTime());
            //===============01.正常执行任务======================
            try {
               /* KeyOperationService keyOperationService = ContextWrapper
                        .getBean("keyOperationService", KeyOperationService.class);*/
                updateFlag = keyOperationService.updateCEBKey();
            } catch (Exception e) {
                logger.error("更新光大密钥失败!", e);
            }
    
            //===============02.执行结果判定======================
            if (!updateFlag) {//如果更新失败,创建一次性任务再次执行(Job仍然是当前class)
                createJob(2);
            }
            logger.info("-------------------update ECB key job end:{} ----------------",
                    DateTimeUtil.getCurrentDateTime());
        }

    7、单元测试 或  手工添加任务的Controller

    单元测试不解释,如果使用了界面,编写的Controller如下

     
    import com.shengpay.mf.constant.ServerErrorEnum;
    import com.shengpay.mf.exception.ServerException;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.quartz.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Description: 定时任务 管理
     * <p/>
     * User: lishaohua
     * Date: 2017/11/14  13:22
     */
    @Controller
    @Api("定时任务管理")//描述类的作用(Swagger注解)
    public class JobController {
        private static Logger logger = LoggerFactory.getLogger(JobController.class);
    
        /*@Autowired
        private SchedulerFactoryBean schedulerFactoryBean;*/
    
        @Autowired
        private Scheduler scheduler;
    
    
        /**
         * 添加定时任务
         *
         * @param request
         * @param jobClassName
         * @param jobGroupName
         * @param cronExpression
         * @return
         */
        @ApiOperation("添加定时任务")//描述方法的作用(Swagger注解)
        @RequestMapping(value = "/addJob", method = {RequestMethod.POST})
        @ResponseBody
        public Map<String, String> addJob(HttpServletRequest request,
                                          @RequestParam(value = "jobClassName") String jobClassName,
                                          @RequestParam(value = "jobGroupName") String jobGroupName,
                                          @RequestParam(value = "cronExpression") String cronExpression) {
            Map<String, String> returnData = new HashMap<String, String>();
            try {
                /**
                 * 构建JobDetail(表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容)
                 */
                JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass())//工作项1:Job类
                        .withIdentity(jobClassName, jobGroupName)//工作项2:job名以及所属组
                        .build();//构建
    
                /**
                 * 构建触发器Trigger(调度参数的配置,代表何时触发该任务)
                 */
                //通过cron表达式构建CronScheduleBuilder
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
                //构建CronTrigger触发器
                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity(jobClassName, jobGroupName) //工作项1:job名以及所属组
                        .withSchedule(scheduleBuilder) //工作项2:指定调度参数
                        .build();//构建
    
                /**
                 *构建调度容器(当Trigger与JobDetail组合,就可以被Scheduler容器调度了)
                 * 一个调度容器中可以注册多个JobDetail和Trigger。
                 */
                //获得调度容器
                //Scheduler scheduler = getCurrentScheduler();
                //注册调度任务
                scheduler.scheduleJob(jobDetail, trigger);
                //启动任务
                scheduler.start();
    
                returnData.put("msg", "添加调度任务成功");
            } catch (SchedulerException e) {
                logger.error("构建调度任务异常", e);
                returnData.put("msg", "添加调度任务异常:" + e.getMessage());
            } catch (ServerException e) {
                logger.error("内部异常", e);
                returnData.put("msg", "添加调度任务异常:" + e.getMessage());
            } catch (Exception e) {
                logger.error("添加调度任务异常", e);
                returnData.put("msg", "添加调度任务异常:" + e.getMessage());
            }
    
            return returnData;
        }
    
        @ApiOperation("暂停定时任务")//描述方法的作用(Swagger注解)
        @RequestMapping(value = "/pauseJob", method = {RequestMethod.POST})
        @ResponseBody
        public Map<String, String> pauseJob(HttpServletRequest request,
                                            @RequestParam(value = "jobClassName") String jobClassName,
                                            @RequestParam(value = "jobGroupName") String jobGroupName) {
            Map<String, String> returnData = new HashMap<String, String>();
            try {
                //获得调度容器
                //Scheduler scheduler = getCurrentScheduler();
                //JobKey定义了job的名称和组别
                JobKey jobKey = JobKey.jobKey(jobClassName, jobGroupName);
                //暂停任务
                scheduler.pauseJob(jobKey);
    
                returnData.put("msg", "暂停调度任务成功");
            } catch (SchedulerException e) {
                logger.error("暂停调度任务异常", e);
                returnData.put("msg", "暂停调度任务异常:" + e.getMessage());
            } catch (Exception e) {
                logger.error("暂停调度任务异常", e);
                returnData.put("msg", "暂停调度任务异常:" + e.getMessage());
            }
    
            return returnData;
        }
    
        @ApiOperation("继续定时任务")//描述方法的作用(Swagger注解)
        @RequestMapping(value = "/resumeJob", method = {RequestMethod.POST})
        @ResponseBody
        public Map<String, String> resumeJob(HttpServletRequest request,
                                             @RequestParam(value = "jobClassName") String jobClassName,
                                             @RequestParam(value = "jobGroupName") String jobGroupName) {
            Map<String, String> returnData = new HashMap<String, String>();
            try {
                //获得调度容器
                //Scheduler scheduler = getCurrentScheduler();
                //JobKey定义了job的名称和组别
                JobKey jobKey = JobKey.jobKey(jobClassName, jobGroupName);
                //继续任务
                scheduler.resumeJob(jobKey);
    
                returnData.put("msg", "继续调度任务成功");
            } catch (SchedulerException e) {
                logger.error("继续调度任务异常", e);
                returnData.put("msg", "继续调度任务异常:" + e.getMessage());
            } catch (Exception e) {
                logger.error("继续调度任务异常", e);
                returnData.put("msg", "继续调度任务异常:" + e.getMessage());
            }
    
            return returnData;
        }
    
        /**
         * 更新定时任务:
         * --传入的triggerKey有与之匹配的
         * --旧触发器的触发时间没有完成
         *
         * @param request
         * @param jobClassName
         * @param jobGroupName
         * @param cronExpression
         * @return
         */
        @ApiOperation("更新定时任务")//描述方法的作用(Swagger注解)
        @RequestMapping(value = "/rescheduleJob", method = {RequestMethod.POST})
        @ResponseBody
        public Map<String, String> rescheduleJob(HttpServletRequest request,
                                                 @RequestParam(value = "jobClassName") String jobClassName,
                                                 @RequestParam(value = "jobGroupName") String jobGroupName,
                                                 @RequestParam(value = "cronExpression") String cronExpression) {
            Map<String, String> returnData = new HashMap<String, String>();
            try {
                //获得调度容器
                //Scheduler scheduler = getCurrentScheduler();
    
                //构建旧的TriggerKey
                TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
                //通过cron表达式构建CronScheduleBuilder
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
                //从调度容器中获取旧的CronTrigger
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                //更新CronTrigger
                trigger = trigger.getTriggerBuilder()
                        .withIdentity(triggerKey) //工作项1:job名以及所属组
                        .withSchedule(scheduleBuilder) //工作项2:指定调度参数
                        .build();//构建
    
                //更新调度任务
                scheduler.rescheduleJob(triggerKey, trigger);
    
                returnData.put("msg", "更新调度任务成功");
            } catch (SchedulerException e) {
                logger.error("更新调度任务异常", e);
                returnData.put("msg", "更新调度任务异常:" + e.getMessage());
            } catch (ServerException e) {
                logger.error("内部异常", e);
                returnData.put("msg", "更新调度任务异常:" + e.getMessage());
            } catch (Exception e) {
                logger.error("更新调度任务异常", e);
                returnData.put("msg", "更新调度任务异常:" + e.getMessage());
            }
    
            return returnData;
        }
    
    
        @ApiOperation("删除定时任务")//描述方法的作用(Swagger注解)
        @RequestMapping(value = "/removeJob", method = {RequestMethod.POST})
        @ResponseBody
        public Map<String, String> removeJob(HttpServletRequest request,
                                             @RequestParam(value = "jobClassName") String jobClassName,
                                             @RequestParam(value = "jobGroupName") String jobGroupName) {
            Map<String, String> returnData = new HashMap<String, String>();
            try {
                //获得调度容器
                //Scheduler scheduler = getCurrentScheduler();
                //TriggerKey定义了trigger的名称和组别
                TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
    
                //暂停触发器
                scheduler.resumeTrigger(triggerKey);
                //暂停触发器
                scheduler.unscheduleJob(triggerKey);
                //移除任务
                scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
    
                returnData.put("msg", "删除调度任务成功");
            } catch (SchedulerException e) {
                logger.error("删除调度任务异常", e);
                returnData.put("msg", "删除调度任务异常:" + e.getMessage());
            } catch (Exception e) {
                logger.error("删除调度任务异常", e);
                returnData.put("msg", "删除调度任务异常:" + e.getMessage());
            }
    
            return returnData;
        }
    
        /**
         * 获得调度容器Scheduler
         *
         * @return
         * @throws SchedulerException
         */
        /*private Scheduler getCurrentScheduler() throws SchedulerException {
            // 实例化Quartz默认的调度器工厂SchedulerFactory
            //SchedulerFactory sf = new StdSchedulerFactory();
            // 获得调度容器
            //Scheduler sched = sf.getScheduler();
            //return sched;
            //Scheduler sched = schedulerFactoryBean.getScheduler();
            //return sched;
        }*/
    
    
        /**
         * 获得指定的类实例
         *
         * @param classname
         * @return
         * @throws ServerException
         */
        private Job getClass(String classname) throws ServerException {
            Job baseJob = null;
            try {
                //加载参数指定的类
                Class<?> classTmp = Class.forName(classname);
                //实例化
                baseJob = (Job) classTmp.newInstance();
            } catch (ClassNotFoundException e) {
                logger.error("找不到指定的类", e);
                throw new ServerException(ServerErrorEnum.INTERNAL_ERROR);
            } catch (InstantiationException e) {
                logger.error("实例化类失败", e);
                throw new ServerException(ServerErrorEnum.INTERNAL_ERROR);
            } catch (IllegalAccessException e) {
                logger.error("实例化类失败", e);
                throw new ServerException(ServerErrorEnum.INTERNAL_ERROR);
            }
    
            return baseJob;
        }
    }

    注意:

    在controller层直接注入Scheduler即可,如下:

     @Autowired
     private Scheduler scheduler;

    然后方法中直接调用

                //注册调度任务
                scheduler.scheduleJob(jobDetail, trigger);
                //启动任务
                scheduler.start();

    或者注入声明的

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    然后方法中先执行schedulerFactoryBean.getScheduler()获得scheduler

                //获得调度容器
                Scheduler scheduler = schedulerFactoryBean.getScheduler();
                //注册调度任务
                scheduler.scheduleJob(jobDetail, trigger);
                //启动任务
                scheduler.start();

    但是,一定要注意,千万不要自己直接去new StdSchedulerFactory(),默认的schedulerFactoryBean或注入的scheduler都是被StdScheduler,

    new StdSchedulerFactory()获得的Scheduler将无法被Spring管理,如下代码:
            // 实例化Quartz默认的调度器工厂SchedulerFactory
            SchedulerFactory sf = new StdSchedulerFactory();
            // 获得调度容器
            Scheduler sched = sf.getScheduler();

     创建的任务区别如下:

    ===================================华丽的分割线======================================

    如果不需要让Spring管理quartz生成的job,则每个job作为普通的Bean对象,可以直接通过applicationContext对象直接getBean

    代码如下

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    /**
     * Description: applicationContext工具类
     * <p/>
     * User: lishaohua
     * Date: 2017/11/16  13:48
     */
    @Component
    public class ApplicationContextUtil implements ApplicationContextAware {
        /**
         * 上下文对象实例
         */
        private static ApplicationContext appContext;
    
        /**
         * Spring自动注入applicationContext对象
         * -- 因此该Bean必须@Component被Spring scan发现
         *
         * @param applicationContext
         * @throws BeansException
         */
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            appContext = applicationContext;
        }
    
        /**
         * 获得applicationContext
         * @return
         */
        public static ApplicationContext getAppContext() {
            return appContext;
        }
    
        /**
         * 根据name获取Bean
         *
         * @param name
         * @return
         */
        public static Object getBean(String name) {
            return getAppContext().getBean(name);
        }
    
        /**
         * 根据class获取Bean
         *
         * @param clazz
         * @param <T>
         * @return
         */
        public static <T> T getBean(Class<T> clazz) {
            return getAppContext().getBean(clazz);
        }
    
        /**
         * 根据name、class获得Bean
         *
         * @param name
         * @param clazz
         * @param <T>
         * @return
         */
        public static <T> T getBean(String name, Class<T> clazz) {
            return getAppContext().getBean(name, clazz);
        }
    }

     通过DB查询已添加的任务,查询SQL如下:

    select TO_CHAR(t.next_fire_time / (1000 * 60 * 60 * 24) +  
           TO_DATE('1970-01-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS')  next_fire_datetime,
           t.*
    from qrtz_triggers t;

    查询效果如图

    参考:

    如何获取SpringBoot项目的applicationContext对象

    参考文章:

    https://www.cnblogs.com/javanoob/p/springboot_schedule.html

    https://www.cnblogs.com/softidea/p/6073495.html

    http://blog.csdn.net/magic_best/article/details/50158125

    http://blog.csdn.net/iycynna_123/article/details/52993542

     http://www.jianshu.com/p/b460171c57ea

  • 相关阅读:
    区块链学习(2)钱包
    区块链学习(1)密钥,公钥和地址
    Ubuntu下安装和开启telnet
    ubuntu下的ppa源使用
    tensorflow中手写识别笔记
    交叉熵解读
    Ubuntu下对executable (application/x-executable)文件创建快捷方式
    Numpy学习笔记(四)
    pycharm问题总结
    Numpy学习笔记(三)
  • 原文地址:https://www.cnblogs.com/huahua035/p/7839834.html
Copyright © 2020-2023  润新知