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

SpringBoot @Scheduled注解失效:部署Tomcat后定时任务未执行

解决@Scheduled注解在Tomcat部署后不执行的问题

我完全懂你此刻的困扰——明明给RetrievePrices类的read()方法加了@Scheduled注解,部署到Tomcat后却完全看不到预期的定时任务执行输出。这种情况通常是几个关键配置环节没踩对,咱们一步步来排查修复:

1. 先确认定时任务的核心开关是否开启

  • 你的Spring Boot主类必须加上@EnableScheduling注解,这是开启Spring定时任务功能的关键开关,没有它的话,所有@Scheduled注解都会被直接忽略。比如主类应该写成这样:
@SpringBootApplication
@EnableScheduling // 这个注解绝对不能忘!
public class YourSpringBootMainClass {
    public static void main(String[] args) {
        SpringApplication.run(YourSpringBootMainClass.class, args);
    }
}
  • 如果用了单独的Spring配置类,也要在配置类上加上@EnableScheduling,确保定时任务的上下文能被正确加载。

2. 检查RetrievePrices类是否被Spring容器管理

  • 要让Spring识别到类里的@Scheduled方法,首先得让这个类成为Spring的Bean。给RetrievePrices加上@Component(或者@Service/@Repository这类 stereotype 注解)就行:
@Component // 必须让Spring接管这个类的实例
public class RetrievePrices {
    @Scheduled(fixedRate = 5000) // 每5秒执行一次的配置
    public void read() {
        // 这里换成日志框架输出会更靠谱,后面会说
        System.out.println("定时任务执行中:" + new Date());
    }
}
  • 要是没加@Component这类注解,就算加了@Scheduled,Spring也找不到这个方法,自然不会执行。

3. 适配Tomcat部署的Spring Boot启动逻辑

  • 当把Spring Boot应用打包成war部署到外部Tomcat时,主类必须继承SpringBootServletInitializer并重写configure方法,不然Tomcat没法正确初始化Spring Boot的上下文:
@SpringBootApplication
@EnableScheduling
public class YourSpringBootMainClass extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(YourSpringBootMainClass.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(YourSpringBootMainClass.class, args);
    }
}
  • 这一步很容易被忽略,war包部署和jar包直接运行的启动逻辑完全不同,没做这个适配的话,Spring上下文可能都没正常启动,定时任务肯定不会工作。

4. 检查POM文件的打包配置

  • 确保POM里的打包方式是war,并且正确排除了Spring Boot自带的Tomcat(避免和外部Tomcat冲突):
<packaging>war</packaging>

<dependencies>
    <!-- Spring Boot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 排除内置Tomcat,防止和外部Tomcat冲突 -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 添加Tomcat Servlet API依赖,仅编译时生效 -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <!-- 其他业务依赖... -->
</dependencies>
  • 要是没排除内置Tomcat,很可能会导致上下文加载异常,间接影响定时任务的执行。

5. 换用规范的日志输出(别再用System.out了)

  • 尽量别用System.out.println,而是用Spring自带的SLF4J日志框架,这样日志会被Tomcat的日志系统捕获,更容易排查问题。比如在RetrievePrices类中注入Logger:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class RetrievePrices {
    private static final Logger logger = LoggerFactory.getLogger(RetrievePrices.class);

    @Scheduled(fixedRate = 5000)
    public void read() {
        logger.info("定时任务read()方法执行,当前时间:{}", System.currentTimeMillis());
    }
}
  • 然后在application.properties里配置日志级别:
logging.level.com.yourpackage=INFO

这样就能在Tomcat的logs目录下的日志文件中看到输出,而不是只依赖控制台。

最后验证步骤

  1. 重新打包war包,确保所有配置都修改到位;
  2. 清空Tomcat的webapps目录下的旧应用,重新部署新war包;
  3. 启动Tomcat,查看启动日志,确认Spring上下文正常加载,并且能看到类似Starting scheduling tasks的日志;
  4. 等待5秒以上,查看日志文件或控制台,确认定时任务的输出。

按照这些步骤排查下来,应该就能解决@Scheduled注解不执行的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:30:22