과정을 즐기자

내부 클래스를 스프링 빈으로 등록할 수 있을까? 본문

Spring

내부 클래스를 스프링 빈으로 등록할 수 있을까?

320Hwany 2023. 7. 7. 17:45

지금까지 톱 레벨 클래스에 @Controller, @Service, @Repository, @Component를 붙여 스프링 빈으로  

등록하였습니다. 등록을 하면 스프링 컨테이너 안에서 기본적으로 싱글톤으로 관리됩니다. 

이때 내부 클래스도 스프링 빈으로 등록할 수 있는 지 궁금증이 생겨 예제, 학습 테스트를 만들어봤습니다.

 

중첩 클래스는 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스 4가지로 나뉩니다. 

여기서 정적 멤버 클래스를 제외한 나머지 클래스 들을 내부 클래스라고 부릅니다.     

 

Hello 라는 톱 레벨 클래스 안에 4가지 중첩 클래스를 만들어보았습니다.

// 톱 레벨 클래스
@Component
public class Hello {

    // 정적 멤버 클래스
    @Component
    static class World1 {

    }

    // 비정적 멤버 클래스
    @Component
    class World2 {

    }

    // 익명 클래스 - 아예 @Component 사용 불가
    Runnable anonymousClass = new Runnable() {
        @Override
        public void run() {
            // 익명 클래스의 구현 내용
        }
    };

    public void helloWorld() {

        // 지역 클래스
        @Component
        class World3 {

        }
    }
}

정적 멤버 클래스, 비정적 멤버 클래스, 지역 클래스는 @Component를 붙여도 컴파일 에러가 발생하지 않았지만 

익명 클래스는 아예 @Component를 사용할 수 없습니다.

어떻게 보면 이름을 가지지 않는 익명 클래스이기 때문에 당연한 결과입니다.

 

이제 학습 테스트를 보겠습니다.

@SpringBootTest
class HelloTest {

    @Autowired
    private AnnotationConfigApplicationContext ac;

    @Test
    @DisplayName("static 클래스는 스프링 빈으로 등록될 수 있지만 내부 클래스는 빈으로 등록될 수 없습니다")
    void test() {
        assertThat(ac.getBean("hello")).isNotNull();
        assertThat(ac.getBean("hello.World1")).isNotNull();

        assertThatThrownBy(() -> ac.getBean("hello.World2"))
                .isInstanceOf(NoSuchBeanDefinitionException.class);
        assertThatThrownBy(() -> ac.getBean("hello.World3"))
                .isInstanceOf(NoSuchBeanDefinitionException.class);
    }
}

위 테스트가 통과합니다. 즉 스프링 빈으로 등록된 클래스는 톱 레벨 클래스, 정적 멤버 클래스 입니다.  

나머지 비정적 멤버 클래스, 익명 클래스, 지역 클래스는 스프링 빈으로 등록할 수 없습니다.  

스프링 빈으로 등록할 수 없는 3가지 클래스의 공통점은 바로 내부 클래스 라는 것 입니다.   

왜 내부 클래스는 스프링 빈으로 등록될 수 없을까요?

내부 클래스의 인스턴스는 바깥 인스턴스에 의존하기 때문입니다. 

 

중첩 클래스 중에서 정적 멤버 클래스는 위치만 톱 레벨 클래스의 내부에 있는 것이지 

바깥 인스턴스가 존재하지 않아도 독립적으로 인스턴스화 할 수 있습니다. 

 

즉 정적 멤버 클래스는 독립적으로 인스턴스화를 할 수 있기 때문에 스프링 빈으로 등록할 수 있고  

내부 클래스는 바깥 인스턴스에 의존하기 때문에 스프링 빈으로 만들 수 없습니다.