사실 사용하는 경우 자체가 거의 없다
상태를 지닌다면 상태를 메서드 내부 변수로 포함시켜서 처리하도록
작성하는 것이 옳은 방법
무거운 프로세스를 초기화하려 할 때는 @Lazy 어노테이션으로
호출 시에만 개별 빈을 부르도록 만들면 되기 때문이다
또한 개별 인스턴스가 필요하면 그냥 new 로 직접 생성해도 된다

스프링 컨테이너에서 Bean 을 어떻게 생성해줄까의 개념
기본적으로 Singleton 방식을 사용
원한다면 prototype 으로 매번 요청시 새로 만드는것이 가능
@Component
@Scope("singleton") // 싱글톤이 디폴트이므로 생략 가능
public class SingletoneBean {
// ...
}
@Component
@Scope("prototype")
public class PrototypeBean {
// ...
}상태를 지닌 경우 + 비동기처리
@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 로 직접 생성해도 된다
생성 → 의존성 주입 → 초기화 → 사용 → 소멸 의 라이프사이클을 가짐
좀더 세분화 하면 아래의 순서를 가짐
1. 스프링 컨테이너 생성
2. 빈 객체 생성 (new)
3. 의존성 주입
4. 초기화 콜백
→ @PostConstruct
→ InitializingBean -> 스프링 의존이라 거의 사장됨, 설정이 복잡함
→ @Bean(initMethod) -> 외부 라이브러리 클래스에 많이 사용
5. 빈 사용
6. 소멸 전 콜백
→ @PreDestroy
→ DisposableBean -> 스프링 의존이라 거의 사장됨, 설정이 복잡함
→ @Bean(destroyMethod)
7. 스프링 컨테이너 종료이 중 @Bean(initMethod = “….”, destroyMethod = “….”) 의 형태는
외부 라이브러리 클래스에 많이 사용됨
빈이 생성되고 의존성 주입 끝난 후 바로 실행되어야 할 작업에 사용
초기 데이터 로딩, 미리 캐싱해서 활용해야 할 경우, 스케줄러의 실행에 많이 사용
빈이 제거되기 직전에 호출
외부 리소스 종료, 임시 파일 삭제, 스케줄러 종료 등에 사용
@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("뮤직 플레이어를 종료합니다...");
}
}