You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加@SchedulerLock后Spring定时任务集成测试报空指针异常

问题根源

添加@SchedulerLock后,Spring会为ScheduleService生成代理对象以实现锁逻辑。测试环境中,代理机制、依赖注入方式或方法访问权限的问题,可能导致代理调用目标方法时,原始对象的依赖未完成注入,从而引发空指针异常。

解决方案

1. 改用构造注入替代字段注入

字段注入可能因代理初始化顺序问题导致依赖未生效,构造注入是Spring推荐的方式,能确保对象创建时依赖已完成注入。
示例代码:

@Service
public class ScheduleService {
    private final SomeService someService;

    // Spring 4.3+可省略@Autowired
    public ScheduleService(SomeService someService) {
        this.someService = someService;
    }

    @Scheduled(cron = "0 0 3 * * ?")
    @SchedulerLock(name = "StatisticService_processStatisticsAtThreeAM", lockAtLeastFor = "PT10M")
    public void methodToSchedule() {
        someService.method();
    }
}

若使用Lombok可简化为:

@RequiredArgsConstructor
@Service
public class ScheduleService {
    private final SomeService someService;

    @Scheduled(cron = "0 0 3 * * ?")
    @SchedulerLock(name = "StatisticService_processStatisticsAtThreeAM", lockAtLeastFor = "PT10M")
    public void methodToSchedule() {
        someService.method();
    }
}

2. 将调度方法改为public访问权限

Spring JDK动态代理仅支持public方法,即便使用CGLIB代理,非public方法的代理逻辑在测试环境中可能存在兼容性问题,改为public可避免此类问题。

3. 强制测试环境使用CGLIB代理

如果ScheduleService未实现接口,可在测试类或配置类中添加注解,强制Spring使用CGLIB代理类:

@EnableAspectJAutoProxy(proxyTargetClass = true)
@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@WithMockUser
@Transactional
public class MyTest {
    // ...测试代码
}

4. 验证测试配置完整性

确保测试类通过@SpringBootTest正确加载主应用的配置(包括@EnableSchedulerLock注解),若测试使用自定义配置类,需包含ShedLock的相关配置逻辑。

5. 贴近实际场景触发调度

测试中若需调用调度方法,建议通过Spring的TaskScheduler触发,而非直接调用代理对象的方法,更贴近生产环境的执行逻辑:

@Autowired
private TaskScheduler taskScheduler;

@Test
void testScheduledMethod() {
    taskScheduler.schedule(() -> service.methodToSchedule(), new Date());
    // 断言逻辑
}

内容的提问来源于stack exchange,提问作者Chimitsu Nagase

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 18:07:46