본문 바로가기
Spring

[Spring] @Component와 컴포넌트 스캔

by dbjh 2019. 12. 17.
반응형

이번 글에서는 @Component와 이 어노테이션이 어떻게 인식이 되며, 어떻게 사용되는지 알아보도록하자.

1. @ComponentScan의 범위


@Component 어노테이션을 명시한 클래스는 @ComponentScan의 내부적인 동작에 의해서 스캐닝 되고 Bean으로 등록된다. 스캐닝되는 범위는 @ComponentScan이 명시된 클래스가 위치한 디렉토리를 포함해서 그 하위 디렉토리들이다.

아래 그림에서는 DemoApplication 클래스가 @ComponentScan을 가지고 있기때문에 해당 클래스가 위치한 디렉토리인 com.example.demo 이하의 경로에 있는 범위를 스캔하는 것이다.

@ComponentScan의 범위

 

SpringBoot에서는 main 메소드를 가지고 있는 클래스에 @SpringBootApplication 어노테이션을 명시하는데,
@SpringBootApplication의 내부를 보면 @ComponentScan을 확장한 것을 알 수 있다.

스프링부트의 시작 클래스

@SpringBootApplication을 ctrl+왼쪽마우스클릭하여 들어가보면 아래와 같이 확인할 수 있다.

@SpringBootApplication의 어노테이션에 내재된 어노테이션들

 

@ComponentScan의 중요한 포인트는 스캐닝할 범위와 범위안에서 어떠한 타입을 제외시킬 것인가? 이다.
@ComponentScan 내부 속성을 살펴보면, excludeFilters 속성을 이용하여 제외할 타입을 설정할 수 있다.


실제 스캐닝은 ​ConfigurationClassPostProcessor​라는 ​BeanFactoryPostProcessor​에 의해 처리 되는데,
BeanFactoryPostProcessor는 다른 Bean들이 등록되기전에 컴포넌트 스캐닝 되어, 미리 Bean등록이 된다.
그러면 미리등록된 BeanFactoryPostProcessor가 @Component 어노테이션을 스캔하는 것이다.

기본적으로 @Component 어노테이션을 명시한 클래스들이 Bean으로 등록이 되는데,
@Controller, @Service, @Repository, @Configuration 등이 @Component 를 확장한 어노테이션들이기 때문에 모두 Bean 등록을 위해 명시한다. 해당 빈들은 ApplicationContext에 의해서 생성되는데, Singleton 형태의 경우 프로젝트 구동 시간에 객체를 생성시킨다. 그렇기 때문에 한번 Bean으로 등록되면 또 다시 생성할 필요가 없어서 성능에 영향을 미치지 않는다. 하지만 구동시간이 늦어지도록 영향을 주기 싫다면, Spring5 부터 제공하는  Functional을 방식을 사용하면 된다.


2. 프로젝트 구동완료 후 Bean 등록하기

컴포넌트 스캔을 할때,
@ComponentScan이 명시된 클래스가 있는 디렉토리 이하의 범위만 스캔 한다고 했다. 하지만 범위 밖에있는 클래스를 Bean으로 등록하려면 어떻게 해야할까?라는 생각이 든다면, Function을 이용하여 Bean 등록을 하도록하자.

아래와 같이 @SpringBootApplication가 명시된 DemoApplication 클래스의 디렉토리 범위가 아닌 그 외에 디렉토리에 있는 클래스가 있다.

컴포넌트 스캔의 범위 밖인 AnotherBean

위의 AnotherBean을 프로젝트 구동 이후에 등록하기위해 DemoApplication 클래스의 main 메소드 코드를 수정하도록하자.

// 코드중략

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder().sources(DemoApplication.class)
                .initializers((ApplicationContextInitializer<GenericApplicationContext>) applicationContext -> {
                    applicationContext.registerBean(AnotherBean.class);
                }).run(args);
    }
}

위와 같이 ApplicationContextInitializer의 registerBean 메소드를 이용하여 AnotherBean을 등록하고, 빈이 제대로 등록되는지 확인할 수 있도록 AnotherBean의 코드를 아래와 같이 작성해두도록하자.

 

package exclude;

public class AnotherBean {

    public AnotherBean(){
        System.out.println("Functional AnotherBean 생성");
    }
}

코드 작성을 완료하고 프로젝트를 다시 시작하면,

Function을 사용한 Bean 등록 결과

제대로 Bean등록이 된것을 확인할 수 있다.

 

내용 출처

반응형

댓글