inblog logo
|
LifeLog, DevLog
    Spring

    Bean Scope, Bean 생명주기

    KYJTHEYJ's avatar
    KYJTHEYJ
    Jan 05, 2026
    Bean Scope, Bean 생명주기
    Contents
    Bean ScopeBean의 생명주기

    Bean Scope

    • 스프링 컨테이너에서 Bean 을 어떻게 생성해줄까의 개념

      • 기본적으로 Singleton 방식을 사용

      • 원한다면 prototype 으로 매번 요청시 새로 만드는것이 가능

    스코프 지정법

    @Component
    @Scope("singleton") // 싱글톤이 디폴트이므로 생략 가능
    public class SingletoneBean {
    		// ...
    }
    
    @Component
    @Scope("prototype")
    public class PrototypeBean {
    		// ...
    }

    Prototype의 사용 용도

    • 상태를 지닌 경우 + 비동기처리

    @Component
    public class FileProcessor {
        
        private String fileName; 
        private int processedCount;
        
        public void process(String fileName) {
            this.fileName = fileName;
            this.processedCount = 0;
            
            // 파일 처리...
            while (hasMoreData()) {
                processLine();
                processedCount++;
            }
        }
    }
    
    @Service
    public class FileService {
        
        private final FileProcessor processor;
        
        public void processMultipleFiles() {
      
            new Thread(() -> {
                processor.process("file1.txt");
            }).start();
            
      
            new Thread(() -> {
                processor.process("file2.txt");
            }).start();
            
            // - 같은 FileProcessor 인스턴스 공유
            // - fileName과 processedCount가 섞임
            // - 스레드 안전하지 않음!
        }
    }

    이 경우 스레드가 돌면서 뒤섞이는 경우가 생기는데
    매번 인스턴스를 새롭게 받아 처리하면 된다

    @Component
    @Scope("prototype")
    public class FileProcessor {
        
        private String fileName; 
        private int processedCount;
        
        public void process(String fileName) {
            this.fileName = fileName;
            this.processedCount = 0;
            
            // 파일 처리...
            while (hasMoreData()) {
                processLine();
                processedCount++;
            }
        }
    }
    
    @Service
    public class FileService {
        
        private final ApplicationContext context;
        
        public void processFile(String fileName) {
            // 매번 새로운 인스턴스 생성
            FileProcessor processor = context.getBean(FileProcessor.class);
            processor.process(fileName);
        }
    }
    • 필요할 때만 무거운 프로세스를 처리하려 할 때

    @Component
    @Scope("prototype")
    public class HeavyResourceProcessor {
        
        private LargeDataStructure data;  // 메모리 많이 차지
        
        public HeavyResourceProcessor() {
            // 매우 무거운 초기화
            this.data = new LargeDataStructure();
            System.out.println("무거운 객체 생성!");
        }
        
        public void process() {
            // 처리...
        }
    }
    
    @Service
    public class ProcessService {
        
        private final ApplicationContext context;
        
        public void processWhenNeeded() {
            // 필요할 때만 생성 (평소엔 메모리 차지 안 함)
            if (needsProcessing()) {
                HeavyResourceProcessor processor = 
                    context.getBean(HeavyResourceProcessor.class);
                processor.process();
            }
        }
    }

    💡

    사실 사용하는 경우 자체가 거의 없다

    상태를 지닌다면 상태를 메서드 내부 변수로 포함시켜서 처리하도록
    작성하는 것이 옳은 방법


    무거운 프로세스를 초기화하려 할 때는 @Lazy 어노테이션으로
    호출 시에만 개별 빈을 부르도록 만들면 되기 때문이다

    또한 개별 인스턴스가 필요하면 그냥 new 로 직접 생성해도 된다

    Bean의 생명주기

    생성 → 의존성 주입 → 초기화 → 사용 → 소멸 의 라이프사이클을 가짐

    좀더 세분화 하면 아래의 순서를 가짐

    1. 스프링 컨테이너 생성
    2. 빈 객체 생성 (new)
    3. 의존성 주입
    4. 초기화 콜백 
       → @PostConstruct
       → InitializingBean -> 스프링 의존이라 거의 사장됨, 설정이 복잡함
       → @Bean(initMethod) -> 외부 라이브러리 클래스에 많이 사용
    5. 빈 사용
    6. 소멸 전 콜백 
       → @PreDestroy
       → DisposableBean -> 스프링 의존이라 거의 사장됨, 설정이 복잡함
       → @Bean(destroyMethod)
    7. 스프링 컨테이너 종료

    이 중 @Bean(initMethod = “….”, destroyMethod = “….”) 의 형태는
    외부 라이브러리 클래스에 많이 사용됨

    @PostConstruct

    빈이 생성되고 의존성 주입 끝난 후 바로 실행되어야 할 작업에 사용

    초기 데이터 로딩, 미리 캐싱해서 활용해야 할 경우, 스케줄러의 실행에 많이 사용

    @PreDestory

    빈이 제거되기 직전에 호출

    외부 리소스 종료, 임시 파일 삭제, 스케줄러 종료 등에 사용

    @Component
    public class MusicPlayer {
    
        private List<String> playlist = new ArrayList<>();
    
        // 초기화 콜백: 의존성 주입이 끝난 후 실행
        @PostConstruct
        public void loadPlaylist() {
            System.out.println("--- @PostConstruct 호출 ---");
            playlist.add("아이유 - 라일락");
            playlist.add("BTS - Dynamite");
            System.out.println("플레이리스트 로딩 완료!");
        }
    
        // 소멸 전 콜백: 빈이 사라지기 직전 실행
        @PreDestroy
        public void saveProgress() {
            System.out.println("--- @PreDestroy 호출 ---");
            System.out.println("뮤직 플레이어를 종료합니다...");
        }
    }
    Share article
    Contents
    Bean ScopeBean의 생명주기

    LifeLog, DevLog - https://github.com/KYJTHEYJ

    RSS·Powered by Inblog