一、org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean报 java.io.NotSerializableException异常,需要自己实现QuartzJobBean。
二、dao必须要实现序列化接口,Hibernate dao不能直接继承自HibernateDaoSupport,因为HibernateDaoSupport没有实现序列化接口,只能通过SessionFactory构造HibernateTemplate。
三、当库里己存在Trigger,应用启动时会从库里加载己存在Trigger,会报java.io.InvalidObjectException: Could not find a SessionFactory named: null等SessionFactory等相关异常。因为应用每次启动的得到的SessionFactory实例是不一样的,当从库里取到的Job进行反序列化时,Job里包含的SessionFactory与当前的SessionFactory不一致,所以为null
四、一旦QuartzJobBean类或里面的属性被修改,那么数据库中对应的qrtz_job_details保存的job_class_name还是以前的QuartzJobBean,这导致这个旧的job再一次重新执行时,会找不到相应的QuartzJobBean,而报空指针异常。
第二个问题与第三个是互相关联的,我想到要解决这两个问题的一个方案是Job中不要包含SessionFactory就没一切OK了, 因为SessionFactory是hibernate dao的属性,而hibernate dao是SimpleService的属性,因此SimpleService不能有任何hibernate dao属性了。如此SimpleService业务方法里需要的hibernate dao又如何获取呢?对 spring 的了解,我们知道可以通过ApplicationContext获取到任何spring bean,但是在这里ApplicationContext又怎么获取呢? ... 查看org.springframework.web.context.ContextLoaderListener找到org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext()可以获取到ApplicationContext,增加一个SpringBeanService类,实现序列化接口,通过SpringBeanService可以获取到web己经加载的spring bean
package com.sundoctor.example.service;
import java.io.Serializable;
import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import org.springframework.web.context.ContextLoader;
@SuppressWarnings("unchecked") @Service("springBeanService") public class SpringBeanService implements Serializable{
private static final long serialVersionUID = -2228376078979553838L;
public <T> T getBean(Class<T> clazz,String beanName){ ApplicationContext context = ContextLoader.getCurrentWebApplicationContext(); return (T)context.getBean(beanName); } }
因为Hibernate Dao不再持久到Job中,所在不再需要实现序列化接口,可以继承HibernateDaoSupport,当然也可以不继承,可以根据自己喜好的方式编写,不再有任何限制
package com.sundoctor.example.dao;
import org.hibernate.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.stereotype.Repository;
import com.sundoctor.example.model.Customer; import com.sundoctor.example.service.CustomerService;
@Repository("customerDao") public class CustomerHibernateDao extends HibernateDaoSupport {
private static final Logger logger = LoggerFactory.getLogger(CustomerService.class);
public Customer getCustomer2() { return (Customer) this.getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) { Customer customer = (Customer) session.createQuery("from Customer where id = 1").uniqueResult(); logger.info("Customer2={}", customer); return customer; } }); }
public Customer getCustomer1() { Customer customer = (Customer) this.getHibernateTemplate().get(Customer.class, 1); logger.info("Customer1={}", customer); return customer; }
}
因为hibernate dao 不再实现序列化接口和继承自HibernateDaoSupport,不能再注入到业务类中了。在业务类中注入以上的SpringBeanService,业务方法需要的hibernate dao通过以上的SpringBeanService.getBean获取
package com.sundoctor.example.service;
import java.io.Serializable;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service;
import com.sundoctor.example.dao.CustomerHibernateDao; import com.sundoctor.example.model.Customer;
@Service("customerService") public class CustomerService implements Serializable {
private static final long serialVersionUID = -6857596724821490041L; private static final Logger logger = LoggerFactory.getLogger(CustomerService.class); private SpringBeanService springBeanService;
@Autowired public void setSpringBeanService(@Qualifier("springBeanService") SpringBeanService springBeanService) { this.springBeanService = springBeanService; }
public void testMethod1() { // 这里执行定时调度业务 CustomerHibernateDao customerDao =springBeanService.getBean(CustomerHibernateDao.class,"customerDao"); Customer customer = customerDao.getCustomer1(); logger.info("AAAA:{}", customer);
}
public void testMethod2() { // 这里执行定时调度业务 CustomerHibernateDao customerDao =springBeanService.getBean(CustomerHibernateDao.class,"customerDao"); Customer customer = customerDao.getCustomer2(); logger.info("BBBB:{}", customer); }
customerService是我们的Job具体执行的类,它必须实现序列化,因为它会被序列化到表qrtz_job_details中的job_class_name字段中,所以springBeanService属性也必须序列化,这里其实也可以不用写springbeanservice,而是直接在testMethod中使用applicationContext.getBean去拿到dao,然后进行业务操作。
如果当任务执行的时间点上,正好服务器down掉或由于其他原因任务没有顺利完成
该如何自动或手动唤醒它,让他顺利执行呢?
//获取到Scheduler Scheduler scheduler = ...;//(Scheduler)springContext.getBean("quartzScheduler"); //通过trigger name和trigger group得到SimpleTrigger SimpleTrigger trigger = (SimpleTrigger)scheduler.getTrigger("52f071d3-eebb-4308-abeb-9ce8ec58aba4", "DEFAULT"); //重新设置Trigger己经触发的次数 int timesTriggered = trigger.getTimesTriggered(); trigger.setTimesTriggered(timesTriggered > 0 ? timesTriggered -1 : 0);
//可选,重新设置开始触发时间 //trigger.setStartTime(startTime); //可选,重新设置下次触发时间 //trigger.setNextFireTime(nextFireTime); //等等,还有许多可选配置可以重新设置
//调用rescheduleJob重新调度tirgger scheduler.rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);