Inflearn brand logo image

인프런 커뮤니티 질문&답변

ultimates님의 프로필 이미지
ultimates

작성한 질문수

죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.

0장. 작전1: 시스템 처형 전 무기 점검💀

전략적 침투: Spring Boot Application 실행에대해서

작성

·

112

1

./gradlew bootRun --args='--spring.batch.job.name=systemTerminationSimulationJob'

위에 코드로 터미널에서 실행하는데 System.out.println로 출력해둔 건 나오지않고 스프링부트 로그만 뜨고 끝나버리더군요

AI에게 물어봤더니 그럴경우 강제적으로 하는방법이 있다고해서 ApplicationRunner를 주입시켜서 해봤는데 또 잘나옵니다. ApplicationRunner를 계속 둘수도 없는거라 ApplicationRunner없이 안나오는경우에는 어떠한 설정문제일까요? 일단 AI가 해보라는데로 다해봤지만 실패했습니다.

답변 2

1

KILL-9님의 프로필 이미지
KILL-9
지식공유자

직접 재현해보니 정상적으로 출력된다.

정확한 정보가 필요하구나

1) build.gradle 파일 내용

2) KillBatchSystemApplication 클래스

3) Job 이름 설정


ps. ApplicationRunner 주입따위 필요없다. 뭔가 설정이 꼬인 것 같으니 위 정보를 전달해달라

 

 

 

ultimates님의 프로필 이미지
ultimates
질문자

아래와 같습니다.

1) build.gradle 파일 내용

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.4.7'
    id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.system.batch'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.springframework.boot:spring-boot-starter-batch"
    implementation "org.springframework.boot:spring-boot-starter-jdbc"
    runtimeOnly "com.h2database:h2"
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.batch:spring-batch-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
    useJUnitPlatform()
}

tasks.named("bootRun") {
    jvmArgs "-Dfile.encoding=UTF-8", "-Dsun.stdout.encoding=UTF-8", "-Dsun.stderr.encoding=UTF-8"
}
tasks.withType(JavaCompile).configureEach {
    options.encoding = "UTF-8"
}

2) KillBatchSystemApplication 클래스

package com.system.batch.killbatchsystem;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class KillBatchSystemApplication {
    public static void main(String[] args) {
        System.exit(SpringApplication.exit(SpringApplication.run(KillBatchSystemApplication.class, args)));
    }
}

3) Job 이름 설정

package com.system.batch.killbatchsystem.config;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.concurrent.atomic.AtomicInteger;

@Configuration
public class SystemTerminationConfig {
    private  AtomicInteger processKilled = new AtomicInteger(0);
    private final int TERMINATION_TARGET = 5;

    private final JobRepository jobRepository;
    private final PlatformTransactionManager transactionManager;

    public SystemTerminationConfig(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        this.jobRepository = jobRepository;
        this.transactionManager = transactionManager;
    }

    @Bean
    public Job systemTerminationSimulationJob(){
        return new JobBuilder("systemTerminationSimulationJob", jobRepository)
                .start(enterWorldStep())
                .next(meetNPCStep())
                .next(defeatProcessStep())
                .next(completeQuestStep())
                .build();
    }


    @Bean
    public Step enterWorldStep(){
        return new StepBuilder("enterWorldStep", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("접속완료");
                    return RepeatStatus.FINISHED;
                }, transactionManager)
                .build();
    }

    @Bean
    public Step meetNPCStep(){
        return new StepBuilder("meetNPCStep", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("시스템 관리자 NPC만남");
                    System.out.println("첫번째 미션: 좀비 프로세스 " + TERMINATION_TARGET + "개 처형하기");
                    return RepeatStatus.FINISHED;
                }, transactionManager)
                .build();
    }

    @Bean
    public Step defeatProcessStep(){
        return new StepBuilder("defeatProcessStep", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    int terminated = processKilled.incrementAndGet();
                    System.out.println("좀비 프로세스 처형 완료! (현재 " + terminated + "/" + TERMINATION_TARGET + ")");
                    if(terminated < TERMINATION_TARGET){
                        return RepeatStatus.CONTINUABLE;
                    }else{
                        return RepeatStatus.FINISHED;
                    }
                }, transactionManager)
                .build();
    }

    @Bean
    public Step completeQuestStep(){
        return new StepBuilder("completeQuestStep", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("미션 완료! 좀비 프로세스 " + TERMINATION_TARGET + "개 처형성공!");
                    System.out.println("보상: kill -9 권한획득, 시스템 제어 레벨 1달성");
                    return RepeatStatus.FINISHED;
                }, transactionManager)
                .build();
    }


}
KILL-9님의 프로필 이미지
KILL-9
지식공유자

좋다. 실행 결과 화면과 프로퍼티 설정도 보여달라

 


ultimates님의 프로필 이미지
ultimates
질문자

application.yml

spring:
  batch:
    job:
      enabled: true
      name: systemTerminationSimulationJob
  main:
    web-application-type: none
logging:
  level:
    org.springframework.batch: INFO

실행결과

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :bootRun

. ____ _ __ _ _

/\\ / ___'_ __ _ ()_ __ __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

\\/ ___)| |_)| | | | | || (_| | ) ) ) )

' |____| .__|_| |_|_| |_\__, | / / / /

=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v3.4.7)

2025-08-10T18:15:26.056+09:00 INFO 200768 --- [ main] c.s.b.k.KillBatchSystemApplication : Starting KillBatchSystemApplication using Java 17.0.16 with PID 200768 (C:\Users\XXX\IdeaProjects\kill-batch-system\build\classes\java\main started by XXXin C:\Users\XXX\IdeaProjects\kill-batch-system)

2025-08-10T18:15:26.056+09:00 INFO 200768 --- [ main] c.s.b.k.KillBatchSystemApplication : No active profile set, falling back to 1 default profile: "default"

2025-08-10T18:15:26.487+09:00 INFO 200768 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'

2025-08-10T18:15:26.833+09:00 INFO 200768 --- [ main] c.s.b.k.KillBatchSystemApplication : Started KillBatchSystemApplication in 1.114 seconds (process running for 2.314)

2025-08-10T18:15:26.833+09:00 INFO 200768 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Shutting down embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false'

BUILD SUCCESSFUL in 8s

4 actionable tasks: 3 executed, 1 up-to-date

 

이상입니다

KILL-9님의 프로필 이미지
KILL-9
지식공유자

현재 너와 동일 build.gradle / property 구성으로도 정상 실행되는것이 확인된다


0장 강의에서 다룬 코드 외에 다른 코드들이 침투해있는 것 같다 나머지 코드들도 전부 부탁한다 스프링부트 자동 구성을 누군가가 헤치고있는것으로 파악된다 예를들어 DefaultBatchConfiguration 을 상속한코드가있다거나 


ultimates님의 프로필 이미지
ultimates
질문자

프로젝트를 아에 새로만들어서 전략적침투에 나와있는 코드를 넣어서 돌려도 안나오는군요....

혹시 스프링부트 버전과 관련이 있을 수 있을까요?

KILL-9님의 프로필 이미지
KILL-9
지식공유자

spring batch를 부트가 인식 못하는것으로보인다

1) 전체 프로젝트 구성과 작성한 모든 클래스코드를 전달해달라 

2) Gradle 의존성이 제대로 로드되고 있는지 확인해보자.

./gradlew dependencies --configuration compileClasspath | grep -A 5 -B 5 batch

./gradlew dependencies --configuration runtimeClasspath | grep -A 5 -B 5 batch

 

 

ultimates님의 프로필 이미지
ultimates
질문자

Gradle 의존성체크 입니다 문제가없어보여요 뭐이런경우가....

compileClasspath - Compile classpath for source set 'main'.

\--- org.springframework.boot:spring-boot-starter-batch -> 3.5.4

+--- org.springframework.boot:spring-boot-starter:3.5.4

| +--- org.springframework.boot:spring-boot:3.5.4

| | +--- org.springframework:spring-core:6.2.9

| | | \--- org.springframework:spring-jcl:6.2.9

| | \--- org.springframework:spring-context:6.2.9

--

| +--- org.springframework:spring-beans:6.2.9 (*)

| +--- org.springframework:spring-core:6.2.9 (*)

| \--- org.springframework:spring-tx:6.2.9

| +--- org.springframework:spring-beans:6.2.9 (*)

| \--- org.springframework:spring-core:6.2.9 (*)

\--- org.springframework.batch:spring-batch-core:5.2.2

+--- org.springframework.batch:spring-batch-infrastructure:5.2.2

| +--- org.springframework:spring-core:6.2.4 -> 6.2.9 (*)

| \--- org.springframework.retry:spring-retry:2.0.11 -> 2.0.12

+--- org.springframework:spring-aop:6.2.4 -> 6.2.9 (*)

+--- org.springframework:spring-beans:6.2.4 -> 6.2.9 (*)

+--- org.springframework:spring-context:6.2.4 -> 6.2.9 (*)

 

KILL-9님의 프로필 이미지
KILL-9
지식공유자

 

전체코드가 필요하다
총 몇개 클래스가있는가 정상적으로 구성했다면 위에 말한 
SystemTerminationConfig와 KillBatchSystemApplication만 있어야 정상이다 다른 클래스는 작성하지 않았나?

 

ultimates님의 프로필 이미지
ultimates
질문자

설마 BatchConfig를 만들면안된다는건가요? 만들었었는데.. 삭제하니까되네요?ㅋㅋㅋㅋ

KILL-9님의 프로필 이미지
KILL-9
지식공유자

좋다 내가 질문을 너무 돌려서했다 BatchConfig extends DefaultBatchConfiguration 이 코드가 분명 존재할것같았다

다행이다 얼른 1장으로 넘어가라 0장에서 너무 오랜시간을 지체했다

덕분에 나도 퇴근이다 

화이팅이다 강의 끝까지 포기말고 따라가주길 바란다 💀💀
(새벽 피로감 이슈로 킬구 컨셉을 제대로 구현못했다 이해바란다ㅋㅋ)


ultimates님의 프로필 이미지
ultimates
질문자

감사합니다 덕분에 해결했네요 오랫동안봐서그런지 구조라던지 다외워버렸습니다. 이런거 해결해가는맛에 강의보고있어요

KILL-9님의 프로필 이미지
KILL-9
지식공유자

응원한다 현재 spring boot3.5를 사용하는것으로보인다 그럴 경우 (아주 사소한 변경에 불과하지만) 5장에서 소개하는 일부 코드와 살짝 차이가있을것이다 이를 참고하도록하라
(그리고 우리 강의의 규칙은 형과 반말이다 참고하라 💀)

 

0

안녕하세요, 인프런 AI 인턴입니다.

ultimates님이 겪고 계신 문제는 Spring Boot 애플리케이션에서 배치 작업이나 명령어 실행과 관련된 로그 출력 문제인 것 같습니다. 해당 현상은 보통 Spring Boot의 실행 방식에 관련되어 있으며, 서버 측에서나 로컬 환경에서의 차이로 인해 발생할 수 있습니다.

문제 설명

  • ./gradlew bootRun --args='--spring.batch.job.name=systemTerminationSimulationJob' 명령어를 통해 애플리케이션을 실행할 때 표준 출력(System.out.println)이 제대로 보이지 않는다고 하셨습니다.
  • ApplicationRunner를 사용하면 출력이 잘 나오지만, 항상 사용할 수 없는 상황이라는 점도 설명하셨습니다.

잠재적인 원인 및 해결책

  1. 로그 설정 확인

    • Spring Boot는 기본적으로 SLF4J와 같은 로깅 프레임워크를 사용합니다. 간혹 application.properties나 application.yml에서 로그 레벨이나 출력 옵션이 조정되어 있을 수 있습니다. 이 경우 제대로 설정되어 있는지 확인해보시기 바랍니다.
    • 로깅 레벨을 DEBUG로 설정하면 좀 더 많은 정보를 출력을 받을 수 있습니다.
  2. 환경 변수 및 Gradle 설정 확인

    • Gradle의 경우, 환경 변수나 특정 실행환경에 따라 제대로 출력이 안 될 수도 있습니다. 환경 변수에 TERM 관련 설정이 있어 변화가 생길 수 있습니다.
  3. Spring Boot 애플리케이션 실행 옵션 조정

    • ApplicationRunner 없이 스프링 애플리케이션 내에서 특정 로그를 확인하고자 할 때, CommandLineRunner나 다른 부트스트랩 방법을 사용해보세요. 이곳에서 필요로 하는 로그를 잡울 수 있을 겁니다.
    • SpringApplication.run(Application.class, args); 부분에 추가적인 애프터 실행 로직을 넣어 볼 수 있습니다.
  4. 프로파일 혹은 빌드 옵션

    • 프로파일을 통해 실행되지 않은 경우도 있습니다. 빌드 시나 배포 시 명시적으로 원하는 프로파일을 지정해 보는 것도 추천드립니다.

참조할 수 있는 관련 자료

같은 문제를 겪고 계신 많은 분들을 돕기 위해, 배치와 관련된 깊은 설정 및 문제 해결에 대한 논의가 인프런에서도 자주 얘기되었습니다.
- Spring Boot 애플리케이션에서 로그 출력 제어 관련 논의

해당 링크의 논의들을 통해 유사한 문제의 해결 사례를 참고해 보시길 추천드립니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

ultimates님의 프로필 이미지
ultimates

작성한 질문수

질문하기