Quartz Job中@PostConstruct初始化的成员在execute方法中为空的原因
嘿,这个问题我之前在项目里也踩过坑,结合你的代码和描述,主要有这几个可能的原因,咱们一个个说:
1. Quartz创建的Job实例和Spring管理的实例不是同一个
这是最常见的问题!你给Job加了@Component,Spring确实会创建一个实例并执行@PostConstruct的init()方法,但如果Quartz的配置不对,它会自己新建一个Job实例来执行execute()方法——这个新实例完全不受Spring管理,自然不会执行init(),所以restApiConfiguration就是null。
你看到init()运行正常,其实是Spring容器里那个“闲置”的Job实例执行的,而Quartz真正用来执行任务的是另一个全新的实例。
2. @Transactional注解导致的代理问题
你给execute()加了@Transactional,Spring会给这个Job创建一个动态代理对象。如果代理方式是JDK动态代理(因为你实现了Job接口),那么代理对象不会继承原类的成员变量,当你在代理的execute()方法里访问restApiConfiguration时,其实是在访问代理对象的变量(而不是原实例的),自然就是null。
针对上面的原因,给你两个靠谱的解决办法:
方法一:让Quartz使用Spring管理的Job实例
配置Spring整合Quartz的JobFactory,让Quartz创建Job实例时委托Spring来初始化,这样就能保证Quartz用的是Spring容器里的那个已经执行过init()的实例。
步骤1:自定义SpringJobFactory
@Component public class SpringJobFactory extends SpringBeanJobFactory { private final AutowireCapableBeanFactory beanFactory; public SpringJobFactory(AutowireCapableBeanFactory beanFactory) { this.beanFactory = beanFactory; } @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object jobInstance = super.createJobInstance(bundle); // 让Spring自动装配这个实例,包括执行@PostConstruct beanFactory.autowireBean(jobInstance); return jobInstance; } }
步骤2:配置Scheduler使用这个JobFactory
@Configuration public class QuartzConfig { private final SpringJobFactory springJobFactory; public QuartzConfig(SpringJobFactory springJobFactory) { this.springJobFactory = springJobFactory; } @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); // 设置自定义的JobFactory schedulerFactory.setJobFactory(springJobFactory); // 这里可以添加你的JobDetail和Trigger配置 return schedulerFactory; } }
方法二:改用Spring Boot的@QuartzJob注解(推荐)
如果是Spring Boot 2.4及以上版本,直接用@QuartzJob注解代替@Component和implements Job,Spring会自动帮你完成Quartz和Spring的整合,保证Job实例由Spring管理:
@QuartzJob public class MyQuartzJob { private RestApiConfiguration restApiConfiguration; @PostConstruct public void init() { restApiConfiguration = new ApiConfiguration(); } @Transactional @Scheduled(cron = "0 0/5 * * * ?") // 这里用cron表达式配置触发规则 public void execute() { restApiConfiguration.getWebServiceUrl(); } }
这个方式最省心,不需要手动配置Quartz的JobFactory和Scheduler。
内容的提问来源于stack exchange,提问作者JavaSheriff

