20260820

이상우·2026년 8월 20일

Spring/Java 프로젝트 기준이면 아래 순서로 뒤지면 거의 다 잡힘.

  1. 애노테이션/스케줄러 직접 사용

@Scheduled
@EnableScheduling
SchedulingConfigurer
TaskScheduler
ThreadPoolTaskScheduler
ScheduledTaskRegistrar
ScheduledExecutorService
scheduleAtFixedRate
scheduleWithFixedDelay
Timer
TimerTask

  1. Quartz 계열

Quartz
QuartzJobBean
org.quartz
Scheduler
JobDetail
Trigger
CronTrigger
SimpleTrigger
SchedulerFactoryBean
JobFactory

설정파일도:

spring.quartz
quartz.properties
cronExpression
cron-expression

  1. Spring Batch 자동 실행

@EnableBatchProcessing
JobLauncher
Job
Step
JobRepository
JobExplorer
JobOperator
CommandLineJobRunner

설정:

spring.batch.job.enabled
spring.batch.job.name

그리고 ApplicationRunner, CommandLineRunner 안에서 jobLauncher.run() 하는 경우도 꼭 봐야 함.

  1. 애플리케이션 시작 시 실행되는 코드

@PostConstruct
ApplicationRunner
CommandLineRunner
ApplicationListener
ContextRefreshedEvent
ApplicationReadyEvent
@EventListener

예를 들어 이런 것도 사실상 자동 배치임.

@EventListener(ApplicationReadyEvent.class)
public void run() {
batchService.execute();
}

  1. cron 문자열 자체 검색

cron
0 0
0 *
*/5
fixedRate
fixedDelay

특히 설정파일:

application.yml
application-*.yml
application.properties
bootstrap.yml

에서:

batch:
cron: "0 0 2 * * *"
scheduler:
enabled: true

같은 커스텀 설정이 있을 수 있음.

  1. 프로파일/조건부 활성화

@Profile
@ConditionalOnProperty
@Conditional
matchIfMissing
enabled
scheduler.enabled
batch.enabled

이게 중요한 이유가 이런 식일 수 있어서임.

@ConditionalOnProperty(
name = "batch.scheduler.enabled",
havingValue = "true",
matchIfMissing = true
)

matchIfMissing = true면 로컬 설정에 값을 안 넣었는데도 켜질 수 있음.

  1. Controller가 호출하는 실제 배치 로직 역추적

예를 들어:

BatchController
-> batchService.execute()

를 발견했다면 execute()의 Find Usages를 돌려서:

BatchController
BatchScheduler
BatchJob
ApplicationRunner

전부 확인하는 게 좋음.

오히려 @Scheduled 전체검색보다 이 방식이 더 확실한 경우도 많음.

  1. XML 기반 오래된 프로젝트 구형 Spring이면 Java annotation 없이 XML에 있을 수도 있음.

task:scheduled
task:scheduler
task:annotation-driven

예:

<task:scheduled-tasks>
<task:scheduled
ref="batchService"
method="execute"
cron="0 0 2 * * *"/>
</task:scheduled-tasks>

그래서:

*.xml

도 확인해야 함.

  1. 외부 배치/인프라에서 호출하는 경우

애플리케이션 내부 스케줄러가 아예 없고 외부에서 API를 때릴 수도 있음.

찾아볼 것:

Jenkins
Airflow
Control-M
cron
crontab
Kubernetes CronJob
AWS EventBridge
CloudWatch Events
Spring Cloud Data Flow

특히 Kubernetes 쓴다면:

kind: CronJob
schedule:

검색.

예:

kind: CronJob
spec:
schedule: "0 2 * * *"

그리고 이 CronJob이:

curl POST /batch/run

같이 Controller를 호출할 수도 있음.

  1. DB 자체 Scheduler

애플리케이션이 아니라 DB가 돌리는 경우도 있음.

Oracle:

DBMS_SCHEDULER
DBMS_JOB

PostgreSQL:

pg_cron

SQL Server:

SQL Server Agent

MySQL:

CREATE EVENT
EVENT SCHEDULER

다만 이건 로컬 앱을 띄운다고 바로 따라 실행되는 구조와는 조금 다름.


내가 실제 프로젝트 처음 볼 때는 이 순서로 검색할 듯.

  1. @Scheduled
  2. @EnableScheduling
  3. quartz
  4. cron
  5. JobLauncher
  6. ApplicationRunner
  7. CommandLineRunner
  8. @PostConstruct
  9. ApplicationReadyEvent
  10. batchService 같은 핵심 로직 Find Usages
  11. @ConditionalOnProperty
  12. @Profile
  13. task:scheduled
  14. CronJob

특히 사고 방지 관점에서 제일 중요한 건 @Scheduled만 찾고 끝내지 않는 것.

예를 들어 아래 셋은 전부 @Scheduled가 없어도 자동 실행됨.

ApplicationRunner → batchService
Quartz → batchService
Kubernetes CronJob → BatchController → batchService

그래서 최종적으로는 "실제 배치 로직을 누가 호출하는가"를 역추적하는 것이 가장 확실함.

0개의 댓글