前两天写了一个定时同步数据的问题,但是用着用着就发现问题了,由于我的定时任务用的spring的管理quartz Job类MethodInvokingJobDetailFactoryBean(注:这样的好处是可以自由管控定时调度的执行类、方法、时间等),如图:
但是发现这种方式无法通过注解的方式注入service或数据源,因为它是这种方式定时执行的job方法
/**
* 创建/添加计划任务
*
* @param tbcq
* 计划任务配置对象
* @throws Exception
*/
public void createCronTriggerBean(QuartzTask tbcq) throws Exception {
// 新建一个基于Spring的管理Job类
MethodInvokingJobDetailFactoryBean mjdfb = new MethodInvokingJobDetailFactoryBean();
mjdfb.setName(tbcq.getJobdetailname());// 设置Job名称
// 如果定义的任务类为Spring的定义的Bean则调用 getBean方法
if (tbcq.getIsspringbean().equals("1")) {
mjdfb.setTargetObject(beanFactory.getBean(tbcq.getTargetobject()));// 设置任务类
} else {
// 否则直接new对象
mjdfb.setTargetObject(Class.forName(tbcq.getTargetobject())
.newInstance());// 设置任务类
}
mjdfb.setTargetMethod(tbcq.getMethodname()); // 设置任务方法
mjdfb.setConcurrent(tbcq.getConcurrent().equals("0") ? false : true); // 设置是否并发启动任务
mjdfb.afterPropertiesSet(); // 将管理Job类提交到计划管理类
// 将Spring的管理Job类转为Quartz管理Job类
JobDetail jobDetail = new JobDetail();
jobDetail = (JobDetail) mjdfb.getObject();
jobDetail.setName(tbcq.getJobdetailname());
scheduler.addJob(jobDetail, true); // 将Job添加到管理类
// 新一个基于Spring的时间类
CronTriggerBean c = new CronTriggerBean();
c.setCronExpression(tbcq.getCronexpression()); // 设置时间表达式
c.setName(tbcq.getTriggername()); // 设置名称
c.setJobDetail(jobDetail); // 注入Job
c.setJobName(tbcq.getJobdetailname()); // 设置Job名称
scheduler.scheduleJob(c); // 注入到管理类
scheduler.rescheduleJob(tbcq.getTriggername(), Scheduler.DEFAULT_GROUP,
c); // 刷新管理类
log.info(new Date() + ": 新建" + tbcq.getTriggername() + "计划任务");
}
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
jdbcTemplate = (JdbcTemplate)appContext.getBean("jdbcTemplate");
而后来项目引入redis,又多了一个redisContext.xml的配置文件,这时再执行调度时发现不好使了,因为applicationContext.xml文件中有
而redis配置中引入了很多项目工厂类,例如这种
启动项目时会报错,原因是这种自动装配的属性没有被定义或被set,get,在上面ClassPathXmlApplicationContext是获取了spring的上下文全部内容,于是乎做了简单的修改
ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","redisContext.xml"});
jdbcTemplate = (JdbcTemplate)appContext.getBean("jdbcTemplate");
这时问题解决了,可以正常运行了。
但是同事看后提出了疑问:这样bean是不是会被创建多次,因为在启动项目时spring 中bean已经被实例化了,现在只需要获取对应的bean就可以了。
后来在同事的帮助下用到了更好的实现方式:spring服务定位模式ServiceLocator
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class ServiceLocator implements BeanFactoryAware {
private static BeanFactory beanFactory = null;
private static ServiceLocator servlocator = null;
public void setBeanFactory(BeanFactory factory) throws BeansException {
this.beanFactory = factory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public static ServiceLocator getInstance() {
if (servlocator == null)
servlocator = (ServiceLocator) beanFactory.getBean("serviceLocator");
return servlocator;
}
/**
* 根据提供的bean名称得到相应的服务类
* @param servName bean名称
*/
public static Object getService(String servName) {
return beanFactory.getBean(servName);
}
/**
* 根据提供的bean名称得到对应于指定类型的服务类
* @param servName bean名称
* @param clazz 返回的bean类型,若类型不匹配,将抛出异常
*/
public static Object getService(String servName, Class clazz) {
return beanFactory.getBean(servName, clazz);
}
}
于是乎,我再封装了一下,在原有的调度类中继承一个获取数据源的类
public class DataSourceFactory {
public static JdbcTemplate jdbcTemplate = null;
static{
ServiceLocator service = ServiceLocator.getInstance();
jdbcTemplate = (JdbcTemplate)service.getService("jdbcTemplate");
}
}
public class PvisFlowSynTask extends DataSourceFactory{...}
public void insertFlowHis(final List list){
try {
System.out.println("实时流量pvis数据同步调度 inserting...");
jdbcTemplate.batchUpdate(
"insert into T_UI_FLOWANALYSE_HIS (STATIS_DATE, STATIS_HOUR, AREA_ID, PEO_ID, STATIS_TYPE, USER_COUNT, CYCLE_TYPE) values(?,?,?,?,?,?,?)",
new BatchPreparedStatementSetter() {
public int getBatchSize() {
return list.size();
}
public void setValues(PreparedStatement ps, int i)
throws SQLException {
FlowBean bean = list.get(i);
ps.setString(1, bean.getInsertDate());
ps.setString(2, bean.getBeginTime().substring(8, 12));
ps.setString(3, bean.getAreaId());
ps.setString(4, bean.getPeoId());
ps.setString(5, bean.getStatisType());
ps.setString(6, bean.getTotalCount());
ps.setString(7, bean.getCycleType());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
ok,特此记录下
注:上传不了文件,需要核心源码的可以联系我。