在一个项目里利用Quartz可以实现定时任务,但在与Spring整合后,Job中使用的Service没有注入成功,后台运行空指针异常。
定时任务的java代码如下:
public class RecLogJob implements Job{
@Autowired
private ConfigService configService;
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
//删除配置时间段外的日志信息
configService.deleteRecLog();
}
}
业务层代码如下:
@Service
public class ConfigServiceImpl implements ConfigService {
//这里实现接口方法
}
public interface ConfigService {
//接口方法
}
配置文件如下:
<!--定时删除日志信息 -->
<bean id="recLogJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- durability表示任务完成之后是否依然保留到数据库,默认false -->
<property name="durability" value="true"></property>
<property name="jobClass" value="com.ppm.servlet.RecLogJob"></property>
<!-- <property name="jobDataAsMap">非常重要,用来向JobDetail传参
<map>
<entry key ="configService" value-ref="configService"/>
<entry key="timeout" value="5" />
</map>
</property> -->
</bean>
<!--触发器 -->
<bean id="recLogJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="recLogJobDetail"></property>
<property name="cronExpression" value="0 0 12 * * ?"></property>
</bean>
<!-- 定义核心调度器 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- <property name="jobDetails">
<list>
<ref bean="recLogJobDetail" />
</list>
</property> -->
<property name="triggers">
<list>
<ref bean="recLogJobTrigger"/>
</list>
</property>
</bean>
<!-- <bean id="configService" class="com.ppm.service.implement.ConfigServiceImpl" /> -->
项目运行后,直接后台抛出空指针异常。那么问题出在哪呢?
quarz的job通常会依赖业务对象执行操作,通常这些业务对象可以在job初始化时通过dataMap传入,大家可以看上面的配置文件,注释的地方是我试图用dataMap传入的,但是实际运行还是空指针。
原因原来是在采用数据库持久化Job的模式下,这些业务对象会被持久化,所以需要对业务对象进行序列化操作,但由于很多业务对象无法进行序列化,所以持久化的过程就会报错。
下面说一下解决方案。
方案一:在job执行的方法中加入如下一段代码,这也是最简单的。
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
// 使得job对象可以通过注解实现依赖注入
SpringBeanAutowiringSupport
.processInjectionBasedOnCurrentContext(this);
//删除配置时间段外的日志信息
configService.deleteRecLog();
}
方案二:
通过ClassPathXmlApplicationContext直接获取service实例,如下:
ClassPathXmlApplicationContext context = ApplicationContextHelper.getGlobalContext();
ConfigService configService= (ConfigService ) context.getBean("configService ");
还可以这样:
ApplicationContext context= ContextLoaderListener.getCurrentWebApplicationContext();
ConfigService configService= (ConfigService ) context.getBean("configService ");