스케줄러(Scheduler는 정해진 시간이나 주기마다 특정 작업을 자동으로 실행하는 기능. 백엔드 개발에서는 데이터 백업, 이메일 발송, 정기 리포트 생성 등 다양한 용도로 활용
Spring에서는 스케줄링을 지원하는 여러 가지 방법을 제공합니다. 가장 기본적이고 많이 사용하는 방법은 @Scheduled 어노테이션을 사용하는 것입니다. 이를 사용하기 위해서는 먼저 스케줄링 기능을 활성화해야 합니다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 스케줄링 활성화
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
스케줄러는 주기적으로 실행될 작업을 정의한 메서드에 @Scheduled 어노테이션을 붙여서 작성합니다.
ex) 매 5초마다 콘솔에 매시지 출력
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyScheduler {
// 매 5초마다 실행
@Scheduled(fixedRate = 5000)
public void printMessage() {
System.out.println("스케줄러 작동 중: " + System.currentTimeMillis());
}
}
@Scheduled(cron = "0 0 * * * *") // 매 정시(매 시간 0분 0초)에 실행
public void cronJob() {
System.out.println("크론 스케줄러 작동 중: " + System.currentTimeMillis());
}
Spring의 스케줄링은 기본적으로 스레드 풀을 사용하여 작업을 비동기적으로 실행합니다. 기본 스레드 풀의 크기는 1이지만, 필요에 따라 커스터마이징할 수 있습니다.
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.context.annotation.Bean;
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5); // 스레드 풀 크기 설정
scheduler.setThreadNamePrefix("scheduler-");
scheduler.initialize();
return scheduler;
}
}
@Scheduled(fixedRate = 5000)
public void safePrintMessage() {
try {
// 작업 로직
System.out.println("안전한 스케줄러 작동 중: " + System.currentTimeMillis());
// 예외 발생 가능성 있는 코드
} catch (Exception e) {
// 예외 처리 로직
e.printStackTrace();
}
}
Spring의 기본 스케줄링 기능 외에도 더 복잡한 스케줄링이 필요한 경우 Quartz와 같은 라이브러리를 사용할 수 있습니다. Quartz는 클러스터링, 지속성, 복잡한 트리거 등을 지원합니다. 그러나 신입 개발자라면 기본 @Scheduled 기능을 먼저 익히는 것이 좋습니다.
ex) 매일 자정에 데이터베이스 백업
@Component
public class BackupScheduler {
@Scheduled(cron = "0 0 0 * * *") // 매일 자정에 실행
public void backupDatabase() {
// 데이터베이스 백업 로직
System.out.println("데이터베이스 백업 시작: " + LocalDateTime.now());
// 백업 작업 수행
}
}
매 10분마다 외부 API 호출
@Component
public class ApiScheduler {
@Scheduled(fixedRate = 600000) // 매 10분(600,000 밀리초)마다 실행
public void callExternalApi() {
// 외부 API 호출 로직
System.out.println("외부 API 호출: " + LocalDateTime.now());
// API 호출 코드
}
}
신입 Java/Spring 백엔드 개발자로서 스케줄러(Scheduler)를 실습해보는 것은 매우 유익한 경험이 될 것입니다. 실제로 작동하는 프로젝트를 통해 스케줄링 개념을 이해하고, 이를 응용할 수 있는 능력을 키울 수 있습니다. 아래에 몇 가지 실습 아이디어와 함께 구현 방법을 단계별로 설명드리겠습니다.
@Scheduled 어노테이션 사용법, 기본 스케줄링 설정Spring Boot 프로젝트 생성
Spring Web스케줄링 활성화
@EnableScheduling 어노테이션 추가import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SchedulerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerDemoApplication.class, args);
}
}
스케줄러 컴포넌트 작성
@Scheduled 어노테이션을 사용하여 주기적으로 실행될 메서드 작성import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ConsoleLoggerScheduler {
@Scheduled(fixedRate = 5000) // 5초마다 실행
public void logMessage() {
System.out.println("스케줄러 실행: " + System.currentTimeMillis());
}
}
애플리케이션 실행 및 확인
fixedDelay 또는 cron)로 변경해보기@Scheduled와 연계Spring Boot 프로젝트 생성
Spring Web, Spring Boot Starter Mail 의존성을 추가하여 프로젝트 생성메일 설정 추가
application.properties 파일에 이메일 서버 설정 추가spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=your_email@gmail.com
spring.mail.password=your_password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
스케줄러 컴포넌트 작성
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class EmailScheduler {
@Autowired
private JavaMailSender mailSender;
@Scheduled(cron = "0 0 9 * * *") // 매일 오전 9시에 실행
public void sendDailyEmail() {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo("recipient@example.com");
message.setSubject("일일 보고");
message.setText("안녕하세요,\n오늘의 보고서를 확인해주세요.");
mailSender.send(message);
System.out.println("이메일 발송 완료: " + System.currentTimeMillis());
}
}
애플리케이션 실행 및 확인
Spring Boot 프로젝트 생성
Spring Web, Spring Data JPA 등의 의존성을 추가백업 스케줄러 컴포넌트 작성
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class DatabaseBackupScheduler {
private static final String BACKUP_PATH = "/path/to/backup/";
private static final String DB_NAME = "your_db_name";
private static final String DB_USER = "your_db_user";
private static final String DB_PASSWORD = "your_db_password";
@Scheduled(cron = "0 0 2 * * *") // 매일 새벽 2시에 실행
public void backupDatabase() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String timestamp = LocalDateTime.now().format(formatter);
String backupFile = BACKUP_PATH + DB_NAME + "_" + timestamp + ".sql";
String command = String.format("mysqldump -u%s -p%s %s -r %s", DB_USER, DB_PASSWORD, DB_NAME, backupFile);
try {
Process process = Runtime.getRuntime().exec(command);
int processComplete = process.waitFor();
if (processComplete == 0) {
System.out.println("데이터베이스 백업 성공: " + backupFile);
} else {
System.out.println("데이터베이스 백업 실패");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
주의: 실제 프로젝트에서는 데이터베이스 비밀번호를 코드에 직접 작성하지 않고, 환경 변수나 보안 설정을 통해 관리해야 합니다.
애플리케이션 실행 및 확인
@Scheduled 활용Spring Boot 프로젝트 생성
Spring Web, Spring Data JPA, H2 Database (또는 원하는 DB) 의존성 추가엔티티 및 레포지토리 생성
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class ApiData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String data;
private LocalDateTime timestamp;
// Getters and Setters
}
import org.springframework.data.jpa.repository.JpaRepository;
public interface ApiDataRepository extends JpaRepository<ApiData, Long> {
}
API 호출 스케줄러 컴포넌트 작성
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
@Component
public class ApiCallScheduler {
@Autowired
private ApiDataRepository apiDataRepository;
private RestTemplate restTemplate = new RestTemplate();
@Scheduled(fixedRate = 600000) // 매 10분마다 실행
public void callExternalApi() {
String apiUrl = "https://api.example.com/data"; // 실제 API URL로 변경
try {
String response = restTemplate.getForObject(apiUrl, String.class);
ApiData apiData = new ApiData();
apiData.setData(response);
apiData.setTimestamp(LocalDateTime.now());
apiDataRepository.save(apiData);
System.out.println("API 데이터 저장 완료: " + response);
} catch (Exception e) {
System.out.println("API 호출 실패: " + e.getMessage());
}
}
}
애플리케이션 실행 및 확인
Spring Boot 프로젝트 생성
Spring Web, Spring Data JPA, H2 Database, Jackson 등의 의존성 추가엔티티 및 레포지토리 생성
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class WeatherData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String location;
private String description;
private Double temperature;
private LocalDateTime timestamp;
// Getters and Setters
}
import org.springframework.data.jpa.repository.JpaRepository;
public interface WeatherDataRepository extends JpaRepository<WeatherData, Long> {
}
날씨 API 호출 스케줄러 컴포넌트 작성
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
@Component
public class WeatherDataScheduler {
@Autowired
private WeatherDataRepository weatherDataRepository;
private RestTemplate restTemplate = new RestTemplate();
private ObjectMapper objectMapper = new ObjectMapper();
private static final String API_KEY = "your_api_key"; // 실제 API 키로 변경
private static final String LOCATION = "Seoul";
private static final String API_URL = "http://api.openweathermap.org/data/2.5/weather?q=" + LOCATION + "&appid=" + API_KEY + "&units=metric";
@Scheduled(cron = "0 0 * * * *") // 매 정시마다 실행
public void fetchWeatherData() {
try {
String response = restTemplate.getForObject(API_URL, String.class);
JsonNode root = objectMapper.readTree(response);
String description = root.path("weather").get(0).path("description").asText();
Double temperature = root.path("main").path("temp").asDouble();
WeatherData weatherData = new WeatherData();
weatherData.setLocation(LOCATION);
weatherData.setDescription(description);
weatherData.setTemperature(temperature);
weatherData.setTimestamp(LocalDateTime.now());
weatherDataRepository.save(weatherData);
System.out.println("날씨 데이터 저장 완료: " + description + ", " + temperature + "°C");
} catch (Exception e) {
System.out.println("날씨 데이터 수집 실패: " + e.getMessage());
}
}
}
애플리케이션 실행 및 확인
버전 관리 사용
문서화
에러 핸들링 강화
로깅 활용
SLF4J와 같은 로깅 프레임워크를 사용하여 로그를 체계적으로 관리하세요.테스트 작성
보안 고려
application.properties의 @Value를 사용하여 관리하고, 코드에 직접 노출하지 않도록 주의하세요.위의 실습 프로젝트들은 스케줄러의 기본 개념을 이해하고, 이를 실제 애플리케이션에 적용해보는 데 큰 도움이 될 것입니다. 각 프로젝트를 구현하면서 발생하는 문제를 해결하는 과정에서 실무에서 필요한 문제 해결 능력과 코딩 실력을 향상시킬 수 있습니다. 또한, 이러한 프로젝트를 포트폴리오에 포함시키면 취업 준비 시 큰 강점이 될 것입니다. 꾸준히 실습을 진행하고, 다양한 기능을 추가해보며 자신만의 프로젝트를 완성해보세요. 화이팅입니다!