[Spring] @Configuration을 통한 빈 등록 시 싱글톤 관리

Junseo Kim·2021년 6월 11일
0

Spring

목록 보기
2/7
post-thumbnail

스프링에서 빈을 등록할 때 크게 2가지 방법이 있다.

1) 클래스마다 @Controller, @Service, @Repository와 같은 어노테이션 붙여주기
2) @Configuration 클래스 내부 메서드에 @Bean 어노테이션 붙여주기

2번째 방법으로 빈을 등록 시 어떻게 스프링 컨테이너가 싱글톤으로 빈을 관리하는지에 대해서 알아보려고 한다.

@Configuration과 CGLIB

아래와 같은 @Configuration 클래스를 통해 빈 등록을 할때, stationRepository()는 stationService를 만들 때 한 번, lineService를 만들 때 한 번, 총 2번이 호출 된다.

@Configuration
public class AppConfig {

    @Bean
    public StationService stationService() {
        return new StationServiceImpl(stationRepository());
    }

    @Bean
    public StationRepository stationRepository() {
        return new JdbcStationRepository();
    }

    @Bean
    public LineService lineService() {
        return new LineServiceImpl(stationRepository(), lineRepository());
    }

    // ...
}

그럼 stationService에서 쓰이는 stationRepository()와 lineService에서 쓰이는 stationRepository()new로 생성되기 때문에 서로 다른 인스턴스라고 생각할 수 있다.

하지만 주소값을 찍어보면 서로 같은 인스턴스라는 것을 알 수 있다.

이것이 어떻게 가능할까?

스프링 컨테이너는 기본적으로 빈을 싱글톤으로 관리해준다. 하지만 위의 구조에서는 new 연산이 2번 불린다. 이를 싱글톤으로 관리해주기 위해서 스프링은 @Configuration 어노테이션이 붙어 있다면, 바이트코드를 조작해서 싱글톤으로 빈을 관리한다.

@Configuration 어노테이션이 붙어 있는 클래스 자체도 빈으로 등록된다. 이를 찍어보면 클래스 명 뒤에EnhancerBySpringCGLIB가 붙게된다.(@Configuration대신 @Component 등의 다른 어노테이션을 붙여주면 클래스명만 찍히는 걸 확인할 수 있다.)

// @Configuration
class wooteco.subway.AppConfig$$EnhancerBySpringCGLIB$$58ae7df8
// @Component
class wooteco.subway.AppConfig

즉, @Configuration 어노테이션이 붙은 클래스는 스프링에 의해 빈으로 등록될 때 우리가 만든 클래스가 등록되는 것이 아니라 스프링에 의해 조작된 클래스가 빈으로 등록된다.

@Configuration 어노테이션이 붙은 클래스는 CBLIB을 이용하여 우리가 만든 클래스를 상속받아 임의의 클래스를 만들어주고, 그 클래스가 빈으로 등록되는 것이다. 이 조작된 빈이 싱글톤을 보장해준다.

조작된 클래스는 @Bean 어노테이션이 붙어있는 메서드가 실행될 때, 스프링 컨테이너에 해당 빈이 존재하면 그 빈을 찾아서 반환해주고, 없다면 새로 생성해서 빈으로 등록해주고 반환해준다.

내부 메서드에 @Bean이 붙어 있다면, @Configuration이 없더라도 빈으로 등록은 되지만, 싱글톤은 보장되지 않는다.

CGLIB : 바이트 코드 조작 라이브러리. 런타임에 동적으로 자바 클래스의 프록시를 생성해주는 기능을 제공.

참고로 @Bean이 있다고 다 빈으로 등록되는 건 아니다. ApplicationContext에 직접 설정파일을 줄 땐, 클래스 레벨에 @Component(@Configuration, @Controller, @Service, @Repository)가 없어도 @Bean이 있으면 빈으로 등록해주지만(설정 파일 자체를 넘겨주기 때문), 컴포넌트 스캔으로 빈 등록할 땐, @Component 가 붙어있지 않으면 아에 클래스를 인식하지 못하기 때문에 클래스 내부 메서드에 @Bean이 있어도 빈으로 등록되지 않는다.

0개의 댓글