설정된 시작 지점부터 Component 클래스를 스캔하여 Bean으로 등록해주는 역할을 한다.
@Component를 가지고 있는 클래스들이 Scan되어, Bean으로 등록된다.
대표적인 컴포넌트
@Component: 컴포넌트 스캔 @Controller: Web MVC 코드에 사용되는 어노테이션이다. @RequestMapping, @GetMapping 등을 @Controller 에서만 사용할 수 있다. @Repository: 스프링 비즈니스 로직 @Service: @Component에 추가된 기능은 없다. 보통 웹에서 구성하는 서비스의 단위를 말하고, @Transactional어노테이션과 함께 쓰인다. @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 같은 곳에서만 특별한 용도로 사용.