※ 해당 강의 내용을 필기하고 실습 시 트러블슈팅하는 내용으로 구성됨
※ 강의는 Eclipse 환경이지만, 해당 게시물에선 intelliJ 환경에서 작업
문제 디버깅을 위한 도움말
- 3단계 종료 후 코드 백업: https://github.com/in28minutes/master-spring-and-spring-boot/blob/main/01-spring/03-Step03.md
- 자세한 단계별 변경 사항: https://github.com/in28minutes/master-spring-and-spring-boot/blob/main/01-spring/step-by-step-code-changes/step-by-step-guide.md#section-03
master-spring-and-spring-boot/01-spring/step-by-step-code-changes/step-by-step-guide.md at main · in28minutes/master-spring-and
Spring and Spring Boot Tutorial For Absolute Beginners - 10-in-1 - Spring to Spring Boot to REST API to Full Stack to Containers to Cloud - in28minutes/master-spring-and-spring-boot
github.com
package com.in28minutes.learn_spring_framework.examples.d1;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.ComponentScan;
import java.util.Arrays;
@Component
class ClassA {
// Bean을 생성하고 있는 ClassA
}
@Component
class ClassB {
// ClassA Bean을 사용하여 초기화하는 ClassB
//classB에서 수행되는 초기화 논리
private ClassA classA;
public ClassB(ClassA classA){
// 여기에 자동 작업이 나타나게 됨
//의존성 주입해야 함.
//Logic
System.out.println("Some Initialization logic");
this.classA = classA;
}
}
// public class가 아니면,
// @ComponentScan을 안 붙이면,
// Component scan이 안 되면서 초기화 인식안됨
@Configuration
@ComponentScan
public class LazyInitializationLauncherApplication {
public static void main(String[] args){
try(var context =
new AnnotationConfigApplicationContext
(LazyInitializationLauncherApplication.class)){
}
}
}
- public class LazyInitializationLauncherApplication에서는 ClassB Bean을 사용하지 않고 있다. Spring Context를 실행하면 초기화가 자동으로 이뤄진 것임.
- @ComponentScan과 public 표기 잊을 경우 초기화 인식이 제대로 안 됨!! 유의.
- 즉, Bean을 로드하지 않고 Bean에서 메서드를 호출하지 않아도, 자동으로 Bean이 초기화됨
- @Lazy를 ClassB 상단에 적어 적용하면 이걸 방지할 수 있음. 초기화 논리가 실행되지 않고 Bean 초기화가 일어나지 않음. ClassB Bean은 시작할 때가 아니라 ClassB Bean을 사용할 때 초기화됨.
@Component
class ClassA {
// Bean을 생성하고 있는 ClassA
}
@Component
@Lazy
class ClassB {
// ClassA Bean을 사용하여 초기화하는 ClassB
//classB에서 수행되는 초기화 논리
private ClassA classA;
public ClassB(ClassA classA){
// 여기에 자동 작업이 나타나게 됨
//의존성 주입해야 함.
//Logic
System.out.println("Some Initialization logic");
this.classA = classA;
}
public void doSomething(){
System.out.println("Do Something");
}
}
// public class가 아니면,
// @ComponentScan을 안 붙이면,
// Component scan이 안 되면서 초기화 인식안됨
@Configuration
@ComponentScan
public class LazyInitializationLauncherApplication {
public static void main(String[] args){
try(var context =
new AnnotationConfigApplicationContext
(LazyInitializationLauncherApplication.class)){
System.out.println("Initialization of context is completed");
context.getBean(ClassB.class).doSomething();
}
}
}
ClassB 내부 method를 사용하게끔 하면서, 초기화 로직->loading the Bean -> 사용 하는 흐름이 됨.
즉, ClassB를 사용/참조하려고 할 때만 로드되는 게 Lazy annotaion의 역할임.
- @Lazy : Bean을 지연하여 초기화할지 여부를 나타냄.
- @Component를 사용하는 모든 클래스타 Bean에 어노테이션을 적용한 모든 메서드에 적용할 수 있음.
정리
- Eager initialization(recommended)
- 스프링 Bean에 대한 기본 초기화 방법
- Bean은 시작할 때 즉시 초기화됨
- configuration에서의 에러를 애플리케이션 시작하자마자 발견할 수 있기에 추천
- Lazily Initialization(@Lazy)(비추천, 자주 쓰이지도 않음)
- @Component와 @Bean을 쓰는 거의 모든 곳에서 사용 가능
- Lazy-resolution proxy가 실제 dependency 대신 주입됨
- @Configuration class 에서도 사용 가능
- 그렇게 되면, 모든 @Bean method들이 lazily initialized.
- 복잡한 초기화 논리가 많고 시작 시 지연시키고 싶지 않은 상황이라면 고려해볼만 함.
- application에 Bean이 드물게 사용될 때 사용 가능. 사용할 때만 Bean을 가져올 때.
- 주의
- 사용 시, application 시작 시 spring configuration error는 발생되지 않고, runtime error만 확인 가능할 것.
package com.in28minutes.learn_spring_framework.examples.e1;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
class NormalClass{
}
@Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
class PrototypeClass{
}
@Configuration
@ComponentScan
public class BeanScopesLauncherApplication {
public static void main(String[] args){
try(var context =
new AnnotationConfigApplicationContext
(BeanScopesLauncherApplication.class)){
// Scope가 없는 클래스
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
// 해시코드를 보았을 때, 기본적으로 동일한 Bean이 다시 검색됨
// 반환되는 NormalClass의 instance는 같다.
// Scope가 있는 클래스
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
// context.getBean을 호출할 때마다 새로운 해시코드 값이 나타남.
// PrototypeClass는 새로운(다른) instance를 얻음
// 매번 이 spring context에서 새로운 Bean을 가져오는 것
}
}
}
- SpringFramework에서 생성되는 모든 Bean은 기본적으로 Singleton
- Bean을 요청할 때마다 같은 인스턴스 반환(e.g. NormalClass)
- 하지만 Bean을 참조/요청할 때마다 매번 다른 인스턴스를 생성하고 싶은 경우에는 Prototype을 쓰면 됨(e.g.PrototypeClass)
- @Scope(value= ConfigurableBeanFactory.SCOPE_PROTOTYPE)
정리 : Spring Beans는 특정 scope로 사용되어 정의됨
- Singleton : Spring IoC 컨테이너 당 객체 인스턴스가 하나
- Prototype : Spring IoC 컨테이너 당 객체 인스턴스가 여러 개(일 수 있음)
- 웹 애플리케이션에서만 특정하게 적용되는 scopes in web-aware ApplicationContext
- Request : HTTP request 하나 당 하나의 객체 인스턴스가 생성됨
- Session
- 사용자와 관련되어 있음. 동일 사용자에게 속하는 여러 번의 같은 세션에 속해있을 수 있음.
- user HTTP Session당 하나의 객체 인스턴스가 생성됨
- Application
- web application runtime 당 하나의 객체 인스턴스가 생성됨.
- 즉, 웹 애플리케이션 전체에 객체 인스턴스가 하나인 것임.
- Websocket
- WebSocket 인스턴스 당 객체 인스턴스가 하나
- Java Singleton(GOF) vs Spring Singleton
- Spring Singleton : Spring IoC 컨테이너당 객체 instance 한 개
- Java Singleton(GOF) : JVM 당 객체 instance 하나
- 유의 사항
- JVM에 Spring IoC 컨테이너를 하나만 실행한다면 Spring 싱글톤과 Java 싱글톤은 같은 의미(99%의 경우)
- 하지만 JVM에 Spring IoC 컨테이너 여러 개를 실행하면 Spring 싱글톤은 Java 싱글톤과 달라짐
- 보통은 JVM에 Spring IoC 컨테이너 여러 개를 실행하지는 않음
'스프링부트' 카테고리의 다른 글
Spring @Component vs @Bean (0) | 2025.03.12 |
---|---|
[Spring Boot 3 & Spring Framework 6 마스터하기!] Spring Framework를 사용하여 Java 객체를 생성하고 관리하기 (0) | 2025.02.23 |
[Spring Boot 3 & Spring Framework 6 마스터하기!] Java Spring Framework 시작하기 (0) | 2025.02.23 |
[스피링부트 입문 김영한] javax 및 autowire 에러 발생 (0) | 2024.11.20 |
[스피링부트 입문 김영한] 세팅 (0) | 2024.11.19 |