最近做一个定时任务的需求时出现了springmvc自动注入报空指针的问题,在网上各种查找资料终于解决了。下面分享下这两天的经验。
package com.csot.ecp.web.listener;
import javax.inject.Inject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.csot.ecp.web.timer.JudgeEmailSendLogTimer;
public class JudgeEmailAutoSendListener implements ServletContextListener {
@Inject
private JudgeEmailSendLogTimer rt;
//一开始是采用new JudgeEmailSendLogTimer()的方式去调用其start的方法
@Override
public void contextInitialized(ServletContextEvent event) {
String status ="Judge Email Send Listener start";
event.getServletContext().log(status);
System.out.println(status);
rt.start();
}
@Override
public void contextDestroyed(ServletContextEvent event) {
String status ="Judge Email Send Listener stop";
event.getServletContext().log(status);
System.out.println(status);
if(rt !=null){
rt.stop();
}
}
package com.csot.ecp.web.timer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class JudgeEmailSendLogTimer {
@Inject
private JudgeEmailSendLogTask task;
private final Timer timer =new Timer();
public void start(){
final String time = "08:30:00";
long datespan =24*60*60*1000;
Date startTime;
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd " + time);
try {
startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sdf.format(new Date()));
timer.schedule(task, startTime, datespan);
//task这里开始也是用new JudgeEmailSendLogTask ()的方式去执行timer定时任务,结果发现其run()方法里面@Inject注入的变量
为空
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop(){
timer.cancel();
}
}
然后又是各种找“度娘”,最后发现是new出来的对象并没有交给spring去管理,那你这个类又去注入其它的变量肯定是会报空指针的。
就比如:
public class A{
new B().update();
}
public class B{
@Resource
private C c;
public update(){
c.update();//这里会报空指针
}
}
你c交给spring管理了,那么b也要交给spring管理才行,这样c才能注入到b中,a中new才可以用,A 、 B 、 C 都要给Spring管理, 并且不能new才可以。
这时候候debug发现即使改为全部spring注入也会报空指针。
。。。
又是折腾了半天,最后实在不行只能找高手来帮忙了。
“听君一席话胜读十年书啊!” 突然恍然大悟。
因为spring本身也是一个listener,并不鞥保证spring比web.xml的listener更早加载,这就导致了系统在启动后有可能spring的bean还未初始化。
找到原因问题就好解决了^^
一:在不改动源程序的情况下在listener里面手动再加载一遍spring配置文件,但这对系统性能会有一定的影响。
二:采用Quartz或者spring-Task来实现
最后采用了Spring-Task的方式来实现,虽然没有Quartz那么功能强大,但Spring-Task配置简单,而且我原有的代码也不用做太多改动!其实一开始如果不用Timer直接用Quartz或者Spring-Task就没有多问题了!^_^
下面是最终实现代码:
@Component("judgeEmailSendLogTask") public class JudgeEmailSendLogTask { @Inject private JudgeAccessFacade judgeAccessFacade; @Inject private ArrangeAccessFacade arrangeAccessFacade; @Inject private EmployeeAccessFacade employeeAccessFacade; @Inject private SysMailAccessFacade sysMailAccessFacade; @Inject private JudgeConfigFacade judgeConfigFacade; @Inject private SubActivityAccessFacade subActivityAccessFacade; //系统地址 @Value("${SystemUrl}") private String systemUrl; //评委不可排时间设置页面菜单ID @Value("${JudgeNoArrangeTimeSetId}") private String judgeNoArrangeTimeSetId; private static final Logger LOGGER = LoggerFactory.getLogger(JudgeEmailSendLogTask.class); @Scheduled(cron = "0 30 8 * * ?") public void run() { String subject = "ECP认证安排不可排时间设置"; long nh = 1000 * 60 * 60; try { List<String> sendEmailjudgeCodeList = judgeAccessFacade.queryAllJudgeEmailSendLog(); //去掉重复元素 HashSet<String> set = new HashSet<String>(sendEmailjudgeCodeList); sendEmailjudgeCodeList.clear(); sendEmailjudgeCodeList.addAll(set); SubActivityDTO subActivityDTO = new SubActivityDTO(); List<SubActivityDTO> queryList = subActivityAccessFacade.queryAllSubActivity(subActivityDTO); JudgeArrangeDTO judgeArrangeDTO = new JudgeArrangeDTO(); List<JudgeArrangeDTO> judgeList = arrangeAccessFacade.queryJudgeArranges(judgeArrangeDTO); List<String> AlljudgeCodeList = new ArrayList<String>(); for(JudgeArrangeDTO judgeDTO :judgeList ){ AlljudgeCodeList.add(judgeDTO.getJudgeCode()); } HashSet<String> hset = new HashSet<String>(AlljudgeCodeList); AlljudgeCodeList.clear(); AlljudgeCodeList.addAll(hset); if(AlljudgeCodeList.size()>sendEmailjudgeCodeList.size()){ AlljudgeCodeList.removeAll(sendEmailjudgeCodeList); } for(String alljudgeCodeList:AlljudgeCodeList){ EmployeeDTO employeeDTO = employeeAccessFacade.getEmployeeById(alljudgeCodeList); if (employeeDTO == null) { continue; } String email = employeeDTO.getEmail(); if (StringUtils.isEmpty(email)) { continue; } else { for(SubActivityDTO subActivityDTOList : queryList){ Date applystartdate = subActivityDTOList.getApplyStartDate(); Date currentdate =new Date(); String totalActivityId = subActivityDTOList.getTotalActivityId(); long diff = currentdate.getTime() - applystartdate.getTime(); long hour = diff / nh; if(hour>8.5 && hour<24){ // 发送邮件 //String projectUrl=request.getScheme()+"://"+ request.getServerName()+":"+request.getServerPort()+request.getContextPath(); String mailContent = "Dear " + employeeDTO.getName() + ":<br><br> 请点击以下链接设置不可排时间:" + "<br><br>"+systemUrl+"/?extRoute="+judgeNoArrangeTimeSetId+"a "; boolean result = sysMailAccessFacade.sendMailCommon(subject, mailContent, email, "", ""); if(result == true){ //邮件发送成功将该评委记录到表中 CreateJudgeEmailSendLogCommand command = new CreateJudgeEmailSendLogCommand(); command.setJudgeCode(alljudgeCodeList); command.setJudgeName(employeeDTO.getName()); command.setTotalActivityId(totalActivityId); judgeConfigFacade.createJudgeEmailSendLog(command); } } } } } } catch (Exception e) { LOGGER.error("定时发送邮件失败", e); } } }
有理解错误的地方欢迎指正哈!---