Spring Framework Beans 지연 초기화와 즉시 초기화 알아보기

Soo·2024년 3월 5일

이번 포스팅에서는 지연 초기화에 대해 알아보겠습니다.

스프링 빈의 기본 초기화는 즉시 초기화 입니다.

@Lazy - Bean을 지연하여 초기화할지 여부를 나타냅니다.

아래 코드를 보며 설명을 드리자면

package com.in28minutes.learnspringframework.example.d1;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
class ClassA {

}

@Component
class ClassB {

    private ClassA classA;

    public ClassB(ClassA classA) {
        //Logic
        System.out.println("Some Initialization logic");
        this.classA = classA;
    }
}

@Configuration
@ComponentScan
public class LazyInitializationLauncherApplication {
    public static void main(String[] args) {

        try (var context = new AnnotationConfigApplicationContext
                (LazyInitializationLauncherApplication.class)) {

						Arrays.stream(context.getBeanDefinitionNames())
								.forEach(System.out::println);
        }
    }
}

실행 결과로 Class B 가 생성될 때 ClassA를 주입받아 즉시 초기화하는 걸 알 수 있습니다.

Some Initialization logic //즉시 초기화
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
lazyInitializationLauncherApplication
classA
classB

Process finished with exit code 0

여기서 초기화를 늦추고 사용 시점에 초기화를 하고 싶다면?? 어떻게 해야 할까요? 바로 @Lazy 어노테이션을 사용하면 됩니다.

package com.in28minutes.learnspringframework.example.d1;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
class ClassA {

}

@Component
@Lazy
class ClassB {

    private ClassA classA;

    public ClassB(ClassA classA) {
        //Logic
        System.out.println("Some Initialization logic");
        this.classA = classA;
    }
}

@Configuration
@ComponentScan
public class LazyInitializationLauncherApplication {
    public static void main(String[] args) {

        try (var context = new AnnotationConfigApplicationContext
                (LazyInitializationLauncherApplication.class)) {

        }
    }
}

코드를 실행해 보시면 콘솔창에 아무것도 나오지 않는 것을 확인할 수 있습니다.

@Lazy 어노테이션을 추가 했기 때문에 Spring Bean을 사용하기 전에는 초기화를 하지 않기 떄문입니다.

그럼 이번에는 ClassB 스프링 빈을 사용해 보겠습니다. doSomething() 메서드를 정의하고 사용해 봅시다.

package com.in28minutes.learnspringframework.example.d1;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
class ClassA {

}

@Component
@Lazy
class 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");
    }
}

@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();
        }
    }
}

실행 결과

Initialization of context is completed
Some Initialization logic
Do Something

먼저 컨텍스트가 초기화 되었다는 문장이 나온 뒤 Bean을 사용하기 바로 전에 Bean을 로드합니다. Bean을 사용하려고 할 때 로드되는 겁니다

결론

스프링 빈의 기본 초기화는 즉시 초기화 이고 스프링 빈의 사용을 늦추고 싶다면 @Lazy 어노테이션을 사용하면 됩니다.

하지만, 추천하는 초기화는 즉시 초기화입니다. Why?? 생성 시점에 초기화를 하면 애플리케이션이 실행될때 바로 에러를 발견할 수 있지만 지연 초기화를 사용하면 애플리케이션 실행 시점에 에러를 발견할 수 없습니다. Bean사용 시점에 초기화를 하기 때문에 런타임시에 에러가 날 수 있습니다.

0개의 댓글