스프링을 개발하다보면, 마주치는 녀석이 있다. 아무 생각없이 코딩하면 진짜 아무 생각없이 코딩하게 된다.


<context:component-scan base-package="com.software.XXX" />


스프링을 개발할 때 필요한 개념이긴 한데, 매번 넘어가고 있어서 공부해 둘 필요성을 느꼈다. 매번 Copy&Paste(복붙) 으로 프로젝트를 간간히 넘어가다 보면 사소한 문제를 해결하지 못해 되게 많은 시간을 소비한다. 그러면 많이 빡친다. 관련자료가 영어이기 때문에 서툰 영어실력으로 번역기를 돌렸다.


Spring Component Scanning with @ComponentScan 

애노테이션이 달린 @Component 와 특수한 목적성을 띈 애노테이션들 @Controller, @Service, @Repository 들이 스프링 관리 빈 또는 컴포넌트로 식별될 수 있다. 그리고 스프링은 이러한 애노테이션들이 달린 관리 빈 또는 컴포넌트들을 ApplicationContext에서 작성하고 등록해야 한다. 


하지만 스프링 프레임워크에는 컴포넌트 스캐닝에 대한 기능과 컨트롤러, 서비스, 레파지토리에 대한 애노테이션을 검색하는 기능을 제공하고 ApplicationContext에서는 해당 컴포넌트를 만들고 등록한다.


결국 각각의 빈 클래스에 애노테이션


@Component

@Controller

@Service

@Repository


을 통해서 관련된 클래스가 발견되면, 스프링은 빈 클래스를 인스턴스를 생성하고 스프링 IoC(Inverse of Control) 컨테이너가 로드될 때 ApplicationContext에 등록한다. 


스프링의 ApplicationContext를 초기화하는 동안에, 스프링은 @Autowired, @Inject, @Resource 애노테이션을 발견하고 이를 DI 한다.


여기서 내가 잘못 생각하고 있던게, loC와 DI가 별개의 개념이라고 생각했는데 그것이 아닌 IoC, 즉 제어의 역전을 구현하기 위해서 DI(Dependency Injection)을 사용하는 것이다.


글의 주제에 벗어나지만 그래도 쓰는게 나을 거 같다.


DI(Dependency Injection) 를 잠깐 이야기하자면,


- 각 계층 사이, 각 클래스 사이에 필요로 하는 의존관계를 컨테이너가 자동으로 연결

- 각 클래스 사이의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결

- DL 사용 시 컨테이너 종속성이 증가하여, 이를 줄이기 위해 DI 사용


DL (Dependency Lookup) 에 대해선 다음에 살펴보기. 


결과적으로 xml 코드에서 DI를 이용해 해당 클래스에 대해 컨테이너가 연결해주기 위함으로 이용한다. DI에는 두가지 방법을 할 수 있다.


- Setter Injection ( setter() )

1. 인자가 없는 생성자 또는 인자가 없는 static factory 메소드가 bean 을 인스턴스화 하기 위하여 호출된 후 bean의 setter() 메소드를 호출하여 실체화하는 방식

2. 객체를 생성한 이후 의존성 삽입 방식이기 때문에 구현 시에 좀 더 유연하게 사용이 가능
3. setter() 를 통하여 필요한 값이 할당되기 전까지 객체를 사용할 수 없다.

4. 빈 설정파일에서 <property name="" ref="" /> 사용


- Constructor Injection ( 생성자 )

1. 생성자를 이용해서 클래스 사이의 의존 관계를 연결

2. 생성자에 파라미터를 지정함으로써, 생성하고자 하는 객체가 필요로 하는 것을 명확히 설정

3. setter() 는 해당 필드값이 변하는 것에 비해 생성자로 의존 관계를 연결하기 때문에 final 형태로 값 지정 가능

4. 빈 설정파일에서 <constructor-arg ref="" /> 사용


IoC (Inverse of Control : 제어의 역전) 용어

- bean

스프링에서 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트


- bean factory 

스프링의 IoC 를 담당하는 핵심 컨테이너


- application context

bean factory 를 확장한 IoC 컨테이너


- configuration metadata (설정정보 및 메타정보)

application context 혹은 bean factory 가 IoC 를 적용하기 위해 사용하는 메타정보


- container (IoC container)
    IoC 방식으로 bean을 관리한다는 의미에서 bean factoryapplication context 를 가리킨다.




Component Scan

Component Scan은 XML에 일일히 빈 등록을 하지 않더라도 각 빈 클래스에 애노테이션, @Component를 통하여 자동 빈 등록을 가능케 해준다. base-package 에 명시된 패키지 아래 Annotation이 사용된 클래스를 찾아서 빈 등록을 명시한다.


특정 패키지 아래에 위치한 빈들을 Component Scan 하기 위한 방법은 아래와 같다.


(1) XML에 컴포넌트 스캔을 설정 (XML based Configuration)

<conext:component-scan base-package="com.springframework.sample" />


(2) 자바 파일의 설정 클래스에 애노테이션 설정 (Annotation based Configuration) 

@ComponentScan(basePackage = {"com.springframework.sample"})



이제 componet-scan에 알았으면 그와 관련된 빈 등록을 위한, 즉 의존성 주입(DI)을 위한 애노테이션을 살펴봐야 한다. 아래의 그림을 보자.



그림에서 보다시피 위의 애노테이션들은 스프링 프레임워크에서 @ComponentScan 을 이용하여 자동으로 빈을 식별하고 검색하는데 사용된다. 이러한 애노테이션들은 Stereotype annotations 라고 부른다. 


@Component 일반적인 애노테이션/스테레오 타입이며 스프링 관리 구성 컴포넌트로 모든 클래스에 적용할 수 있다. 그리고 스프링 클래스 경로에서 자동으로 스캐닝을 한다


@Repository, @Service, @Controller 과 함께 @Component의 차이점은 @Component는 특별한 경우이며 다른 애노테이션들은 특정한 용도로 사용된다는 것이다. 


[ 추가내용 20180301 : <context:component-scan> vs <context:annotation-config> ]
<context-component-scan> 을 이용하게 되면 <context-annotation-config> 의 사용이 불필요해진다. 왜냐하면 component-scan은 해당 패키지 아래의 경로에서 애노테이션을 찾아 Bean 등록을 실시하는데 비해 annotation-config는 애플리케이션 컨텍스트에 이미 등록된 bean의 annotation을 활성화하는 역할밖에 수행하지 않기 때문이다.


컴포넌트 스캔이 생성자나 필드등에 범위가 국한되지 않고 전체 빈을 연결할 수 있다. 좀 더 확장되게 사용이 가능하다.


자세한 내용은 여기에

stackoverflow 내용



@Controller : Spring MVC presentation Layer

@Service : Business Layer

@Repository : Persistence / Data Access Layer



@Component

일반적으로 쓰이는 애노테이션이며 classpath 가 스프링의 ComponentScan에 의해서 스캔될 때 @Component 가 명시된 클래스를 식별하고 해당 클래스를 빈으로 생성하여 ApplicationContext에 등록한다.


@Repository

해당 애노테이션은 빈 클래스를 Persistence Layer 혹은 DAO(Data Access Object) Layer의 관리 컴포넌트로 설계되었다. 해당 클래스는 데이터에 접근한다는 것을 스프링에 알린다. 해당 애노테이션은 DAO 메소드에서 던지는 모든 예외들(application specific exceptions, database specific exceptions 등)을 스프링의 DataAccessException으로 변환한다. 


@Service

해당 애노테이션은 Business Layer의 관리 컴포넌트로 설계되었다. 해당 클래스에 비즈니스 로직이 포함되어 있음을 스프링에 알린다.


@Controller

해당 애노테이션은 Bean 클래스를 presentation Layer의 컨트롤러로 설계되었다. 해당 애노테이션과 함께 @RequestMapping을 사용하여 URL을 클래스의 인스턴스 메소드로 매핑한다. 


(수정 : 2018 12 06)

위에 적은 내용은 Spring Boot 를 사용하지 않고 JSP/Servlet 혹은 Spring MVC 를 사용한 것을 의미한다. Spring Boot 상에서는, @SpringBootApplication 을 사용하여 @ComponentScan 애노테이션을 추가하고 특정 패키지 내의 빈을 컨텍스트에 등록 및 추가할 수 있다. 자세한 내용은 하단의 네번째 링크 참조



Posted by doubler
,