来公司的第二周接到了定时任务的开发需求:每天早上十点发送用户报表邮件 。校招新人菜鸟没做过这玩意有些懵(尴尬)于是决定分步写,从excel导出->邮件发送->定时器实现->mapper层返回集接收,前几步都没啥问题,都在service层,可以用main方法单独测试下,可以发送邮件,但是通过service调用mapper时问题就来了——菜鸟踩坑了,抛出java.lang.NullPointerException,下图是代码:
@Component @EnableScheduling @Service("cronTaskService") public class CronTaskServiceImpl implements CronTaskService { @Resource private ExportExcelServiceImpl exportExcelService; @Resource private MailSendServiceImpl mailSendService; private final static Logger log = LoggerFactory.getLogger(CronTaskServiceImpl.class); private static int Count = 0; @Scheduled(cron = "*/10 * * * * ?") @Override public void out(){ new ExportExcelServiceImpl().exportExcel("zhoubaobiao1"); //String filePath = exportExcelService.exportExcel("周报表" + Count++ + ".xls"); //mailSendService.sendEmail(filePath); log.info("-----------success-------\n"); } }
问了组内的前辈(应该也是没做几年),问题解决不了,定位不对。后面又在网上找了许久,在一位博主博文中找到了原因,链接:https://blog.csdn.net/itguangit/article/details/78305278
我的想法是通过new()方法创建ExportExcelServiceImpl对象调用exportExcel()方法,exportExcel()方法中调用mapper层连接云上库,然后实现导出excel数据表到本地,结果就出现了空指针异常
[] 2019-12-19 13:22:20.003 [pool-1-thread-1] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task. java.lang.NullPointerException: null at com.titansaas.cronjob.service.impl.ExportExcelServiceImpl.exportExcel(ExportExcelServiceImpl.java:116) at com.titansaas.cronjob.service.impl.CronTaskServiceImpl.out(CronTaskServiceImpl.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
想法比较美好,但是初接触springboot不知道一个关键问题,new()出来的对象,无论是在对象或是在对象内部通过注解@Resource或者是@Autowired实现自动装配,或者是对方法进行@PostConstruct标记(又挖坑坑自己,引发其他一系列问题),期望spring扫描到其中的mapper对象,都做不到;spring不会对其进行自动装配bean,注入mapper失败,导致mapper层映射无法完成,写好的XML中的SQL无法执行。后来在上博文中找到了原因,重新通过@Resource注解注册上面几个Service层对象,让spring自己完成创建和装配,才解决了问题。不复杂,但是网上很多地方的答案不是需要的,问题定位由于缺乏经验还是花了些时间(哈哈