起因
前几日在做一个项目时需要将spring自带的Schedule定时器做一个升级,因此在框架方面选用了Quartz,不过在上手后还是出现了Job threw an unhandled exception的问题,在debug之后发现是没有获取到service的bean
bean报错解决方案
像bean报错的那就去获取bean
第一种可以采用工具类在springboot启动时就获取bean
@Component
public class SpringContextJobUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
@SuppressWarnings("static-access" )
public void setApplicationContext(ApplicationContext contex)
throws BeansException {
// TODO Auto-generated method stub
this.context = contex;
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
public static String getMessage(String key){
return context.getMessage(key, null, Locale.getDefault());
}
}
//最后通过SpringContextJobUtil.getBean("")的方式获取bean
第二种可以采用将quartz托管给spring的方式去获取bean
@Configuration
public class CustomJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
/**
* Create the job instance, populating it with property values taken
* from the scheduler context, job data map and trigger data map.
*
* @param bundle
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
autowireCapableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
在配置类中增加这个CustomJobFactory
@Configuration
@EnableScheduling
public class QuartzConfig {
@Autowired
private CustomJobFactory customJobFactory;
@SneakyThrows
@Bean
public Scheduler scheduler(){
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 自定义 JobFactory 使得在 Quartz Job 中可以使用 @Autowired
scheduler.setJobFactory(customJobFactory);
scheduler.start();
return scheduler;
}
}
Shiro报错
在解决完bean的问题后,好家伙嘛,shiro又报了一个错,真是葫芦娃救爷爷一个一个来:No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
shiro报错解决方案
这个是因为springboot 定时任务因为ThreadContext未绑定SecurityManager,那么我们就加一个DefaultWebSecurityManager去绑定ThreadContext
@Slf4j
@Component
public class SalaryJob implements Job {
@Resource
private SalaryService salaryService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 调用workJob接口的逻辑
System.out.println("执行计算工资定时任务开始,时间:" + new Date());
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
ThreadContext.bind(manager);
salaryService.calculateSalary();
}
}