본문 바로가기

개발/Spring

[Spring] 컴포넌트 스캔, 의존 관계 자동 주입

ComponentScan이란?

설정된 시작 지점부터 Component 클래스를 스캔하여 Bean으로 등록해주는 역할을 한다.


@Component를 가지고 있는 클래스들이 Scan되어, Bean으로 등록된다.

대표적인 컴포넌트


@Component: 컴포넌트 스캔
@Controller: Web MVC 코드에 사용되는 어노테이션이다. @RequestMapping, @GetMapping 등을 @Controller 에서만 사용할 수 있다.
@Repository: 스프링 비즈니스 로직
@Service: @Component에 추가된 기능은 없다. 보통 웹에서 구성하는 서비스의 단위를 말하고, @Transactional어노테이션과 함께 쓰인다.
@Configuration: 스프링 빈 설정

 

 

ComponentScan의 동작 원리

1. Configuration 파싱
ConfigurationClassParser가 Configuration 클래스를 파싱한다.

2. ComponentScan 설정 내역을 파싱한다.
개발자는 basePackages, basePackesClasses, excludeFilters, includeFilters, lazyInit, nameGenerator, resourcePattern, scopedProxy 등 ComponentScanAnnotationParser가 컴포넌트 후보를 모두 찾고, 스캔하기 위하여 해당 설정을 파싱하여 가져온다.
 
특정 어노테이션을 포함/제외 시킬 수 있다.
- includeFilters : 컴포넌트 스캔 대상으로 추가
- excludeFilters : 컴포넌트 스캔 대상에서 제외

3. Class 로딩
위의 basePackage 설정을 바탕으로 모든 클래스를 로딩해야 한다. ( *.class )
클래스로더를 이용하여 모든 자원을 Resource 인터페이스 형태로 불러온다.

4. 빈 정의 설정
클래스 로더가 로딩한 리소스(클래스)를 BeanDefinition으로 정의해놓는다. 그리고 beanName의 key값으로 BeanDefinitionRegistry에 등록해 놓는다. 생성할 빈에 대한 정의(메타데이터 같은)라고 보면 될것 같다.

5. 빈 생성 & 주입
다시 처음으로 돌아가 AbstractApplicationContext에서 보이는 finishBeanFactoryInitialization(beanFactory); 메소드에서 빈을 생성한다.
위에서 설정한 빈 정의를 바탕으로 객체를 생성하고, 주입한다.

 

 

컴포넌트 스캔 범위

@CompoentScan이 있는 파일의 패키지 아래에 전부 찾는다.
basePackages, basePackageClasses로 지정도 가능하다.
권장 방법은 프로젝트 최상단에 두는 것이다.

 

 

 

 

의존 관계 주입

 

1. 생성자 주입

- 생성자 호출 시점에 딱 1번만 호출된다.
- 불변, 필수, 의존관계에 사용한다.

 

 

생성자가 1개만 있으면 @Autowired를 생략해도 자동 주입된다. (스프링 빈만 해당)

생성자 호출 시점에 딱 1번만 호출된다.

 

 

+ 생성자가 딱 1개 있으면 @Autowired를 생략해도 자동 주입된다.

 

강한 결합
객체 내부에서 다른 객체를 생성하는 것은 강한 결합도를 가지는 구조이다. A 클래스 내부에서 B 라는 객체를 직접 생성하고 있다면, B 객체를 C 객체로 바꾸고 싶은 경우에 A 클래스도 수정해야 하는 방식이기 때문에 강한 결합이다.

느슨한 결합
객체를 주입 받는다는 것은 외부에서 생성된 객체를 인터페이스를 통해서 넘겨받는 것이다. 이렇게 하면 결합도를 낮출 수 있고, 런타임시에 의존관계가 결정되기 때문에 유연한 구조를 가진다.
SOLID 원칙에서 O 에 해당하는 Open Closed Principle 을 지키기 위해서 디자인 패턴 중 전략패턴을 사용하게 되는데, 생성자 주입을 사용하게 되면 전략패턴을 사용하게 된다.

 

 

 

 

2. setter 주입

setter를 통해 필드의 값에 의존 관계를 주입하는 방법.
- 선택, 변경이 가능해야 하는 의존 관계에 사용한다.

 

TestBookRepository Bean이 생성될 때, @Autowried로 의존 관계 주입을 시도하게 된다.

만약 이때 해당하는 Bean이 없다면, 오류를 발생시킨다.

 

하지만 setter를 통해 BookService 의존성 주입을 강제하고 싶지 않다면, 별도의 Optional을 통해 설정해 줄 수 있다.

 

3. 필드 주입

필드에 의존 관계를 주입하는 방법

특징
- 외부에서 변경이 불가능하다.
- DI 프레임워크가 없으면 즉, 스프링 컨테이너를 띄우지 않고 순수한 Java로 하는 단위 테스트가 불가능하다.
- 때문에 스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 특별한 용도로 사용.

 

 

 

 

 

참고

velog.io/@syleemk/Spring-Core-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94%EA%B3%BC-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85

jess-m.tistory.com/14   

yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/