guangjingfenggmail / springqianbailu

springqianbailu
1 stars 0 forks source link

Spring boot框架整合quartz,job类中依赖注入报空指针问题 #7

Open fengmnegchang opened 5 years ago

fengmnegchang commented 5 years ago

type 'org.quartz.Scheduler' in your configuration. @Autowired private Scheduler scheduler; dubbo框架下scheduler编译不过????

fengmnegchang commented 5 years ago

quartz框架进行定时任务的开发。由于定时任务的job类中需要调用其他service的方法,所以必须注入需要的bean。但是在运行项目的时候发现,job类中的依赖注入会报空指针异常。于是从网上查了相关资料,以解决这个问题。  

    quartz有三个核心概念:调度器、任务和触发器。三者关系是,调度器负责调度各个任务,到了某个时刻或者过了一定时间,触发器触动了,特定任务便启动执行。概念相对应的类和接口有:

        1)Job:表示一个工作,要执行的具体内容。此接口中只有一个方法 void execute(JobExecutionContext context)    2)JobDetail:描述任务的相关情况,包括配置任务执行的类和方法。Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。   3)Trigger:描述出发Job执行的时间触发规则。代表一个调度参数的配置,什么时候去调。有SimpleTrigger和CronTrigger两个子类代表两种方式,一种是每隔多少分钟小时执行,则用SimpleTrigger;另一种是日历相关的重复时间间隔,如每天凌晨,每周星期一运行的话,通过Cron表达式便可定义出复杂的调度方案。    4)Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail要注册到Scheduler中才会生效,也就是让调度器知道有哪些触发器和任务,才能进行按规则进行调度任务,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。      在quartz框架中,Job 是通过反射出来的实例,不受spring的管理。Scheduler现在交给Spring生成,在Spirng-context-support  jar包下org.springframework.scheduling.quartz包中有个SpringBeanJobFactory的类,job实例通过该类的createJobInstance方法创建。根据Scheduler context、job data map and trigger data map填充其属性。但是创建的job实例并没被spring管理,这就需要我们自定义一个类将创建的job添加到applicationContext中,该类需要继承SpringBeanJobFactory,并实现ApplicationContextAware接口。

    ApplicationContextAware接口的作用:Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给该类对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。

    重写SpringBeanJobFactory类中的createJobInstance方法,将创建的job实例添加到applicationContext中,交给spring管理。

代码如下:

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements         ApplicationContextAware {

    private transient AutowireCapableBeanFactory autowireCapablebeanFactory;

    @Override     public void setApplicationContext(final ApplicationContext context) {         autowireCapablebeanFactory= context.getAutowireCapableBeanFactory();     }

    @Override     protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {         final Object job = super.createJobInstance(bundle);         autowireCapablebeanFactory.autowireBean(job);         return job;     } }

再将AutowiringSpringBeanJobFactory交给spring管理,job类中依赖注入空指针问题就解决了

@Configuration public class SchedulerConfig {          @Bean     public JobFactory jobFactory(ApplicationContext applicationContext)     {         AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();         jobFactory.setApplicationContext(applicationContext);         return jobFactory;     }

    @Bean     public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws Exception {         SchedulerFactoryBean factory = new SchedulerFactoryBean();         factory.setOverwriteExistingJobs(true);         factory.setJobFactory(jobFactory);         factory.setQuartzProperties(quartzProperties());         factory.afterPropertiesSet();         return factory;     }

    @Bean     public Properties quartzProperties() throws IOException {         PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();         propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));         propertiesFactoryBean.afterPropertiesSet();         return propertiesFactoryBean.getObject();     }

}