스프링 핵심 원리 - 기본편 | 컴포넌트 스캔과 의존관계 자동 주입

Yunny.Log ·2022년 5월 31일
0

Spring Boot

목록 보기
62/80
post-thumbnail

1. 컴포넌트 스캔과 의존관계 자동 주입

  • 지금까진 설정정보에 직접 수동적으로 등록 하는 정보를 나열하는 방식을 취함
  • 실무에서는 이를 일일히 등록하기 어려우며, 설정정보 어렵고 누락하는 위험성 존재
  • 무엇보다 빈을 등록하는 일이 반복된다.

스프링은 그래서

  • 스프링은 설정정보가 없어도 스프링 빈을 자동적으로 등록해주는 컴포넌트 스캔 제공
  • 의존성을 자동으로 주입해주는 @Autowired라는 기능도 제공

새롭게 설정정보 지정해주기

  • 설정 정보니깐 @Configuration 붙여주기

컴포넌트 스캔이란?

  • 스프링 빈을 쫙 끌어와서 자동적으로 빈을 끌어올리는 작업
    - @ComponentScan 이라는 어노테이션을 컴포넌트 스캔 기능을 위해 추가
  • 어노테이션 붙은 빈 찾아서 등록해주는 과정을 거침
  • 컴포넌트 스캔을 통해서 자동으로 지정해줄 때, 빼줄 빈도 선언이 가능
    excludeFilters를 통해서 우리는 기존 예제코드들을 (ex AppConfig) 를 제외해주기 위해서 이를 스캔 대상에서 제외시킨다고 작성해준다.
    (+) 실무에서는 굳이 이렇게 안하고, 컴포넌트 스캔으로 처리한다

=> 이렇게 해주면 @Bean 처럼 하나하나 빈으로 등록해주지 않아도 된다.

  • 이제 빈 등록하지 않고,빈으로 등록하고자 하는 클래스 위에 @Component를 붙여주면 나중에 컴포넌트 스캔이 쫙 돌면서 @Component가 들어가있는 클래스들을 자동으로 등록해주게 됩니다.

=> 구현체들 중 DiscountPolicy 를 구현한 두개 중 내가 사용할, 빈으로 등록할 것에 @Component를 붙여주면서 빈 등록을 진행하면 된다.

그런데 컴포넌트 스캔은 설정정보 지정란이 존재하지 않지

  • 기존에는 @Configuration에서 의존관계를 설정해주었음 but 컴포넌트 스캔 사용할 때는 바로 빈으로 등록해버린다.
  • 즉, 이전에는 설정 정보를 작성해줬었는데 이제는 설정 정보 존재하지 않아서, 의존관계 주입 설정은 빈으로 등록해준 클래스 안에서 구현해야 한다.

그러면 의존성 주입은 how ?

  • 빈으로 등록할 때 생성자에 @Autowired 어노테이션을 붙여주게 된다면 생성자에 존재하는 의존관계를 자동적으로 등록해준다.
  • 즉 클래스 생성할 때 의존관계를 주입해주는 것!
  • 따라서 @ComponentScan을 쓰면 @Autowired를 붙여줌으로써, 자동적으로 맵핑이 되게 하는 동시에 의존성 관계 또한 주입해주게 된다.

이전과 달라진 과정

  • 설정정보로 AppConfig에 이것저것 등록해주지 않고, 단순히 @ComponentScan이 붙은 AutoAppConfig라는 클래스로 설정정보 넘겨준다.

컴포넌트 스캔 (@ComponentScan) 의 과정

  • @ComponentScan은 @Component가 붙은 클래스를 다 뒤진다
  • @Componen 붙은 애를 싱글톤 + 빈으로 등록
  • 이때 저장되는 이름 방식
    => 기본 이름은 클래스명, 앞 글자는 소문자로 변경하기!

의존관계 자동 주입 (@Autowired) 과정

  • 생성자에 @Autowired 지정 시, 스프링 컨테이너가 자동으로 해당 스프링 빈 찾아 주입
  • 기본 전략은 타입이 같은 빈!
  • 생성자에 파라미터 많더라도, 자동으로 주입

2. @ComponentScan 탐색 위치와 기본 스캔 대상

2-1 탐색할 패키지의 시작 위치 지정

  • @ComponentScan 에게 스캔을 시작할 패키지를 지정할 수 있음
  • basePackages : 패키지 지정하면 상위패키지부터 하위패키지로 돌면서 스캔 진행
  • basePackageClasses : 지정한 클래스의 패키지를 탐색 시작 위치로 지정
  • 아무것도 지정안할 시 (디폴트) : @ComponentScan 이 붙은 설정 정보 클래스의 패키지가 시작 위치 => 설정 정보 클래스의 위치를 프로젝트 최상단에

프로젝트메인 설정 정보는 프로젝트를 대표하는 정보, 따라서 프로젝트 시작 루트 위치에 두는 것이 권장됨 / 스프링부트로 진행하면 스프링 부트의 대표 시작 정보인 @SpringBootApplication를 프로젝트 시작 루트에 두는 것이 관례

2-2 : 컴포넌트 스캔 기본 대상

  • @Component : 컴포넌트 스캔에서 사용
  • @Controlller : 스프링 MVC 컨트롤러에서 사용 & 스프링 MVC 컨트롤러로 인식
  • @Repository : 스프링 데이터 접근 계층에서 사용 & 인식 , 데이터 계층의 예외를 스프링 예외로 변환
    - 특정 db에서 예외가 나타나게 되는 경우 존재
    • 이걸 스프링 예외로 변환안해주고, 데이터 계층 예외로 처리하면 나중에 db가 변할 때마다 스프링 안의 로직들이 흔들리게 됨
    • 따라서 해당 로직들의 견고함을 위해서 스프링 예외로 변경해주는 과정을 처리
  • @Configuration : 스프링 설정 정보에서 사용 & 인식, 스프링 빈이 싱글톤으로 유지될 수 있도록 추가 처리
  • @Service : 스프링 비즈니스 로직에서 사용, 별다른 역할은 없고 개발자들에게 비즈니스 로직이 여기 존재한다는 것을 인식시켜주는 용도

3. 필터

3-1 : 어노테이션 만들기

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}

3-2 : 클래스에 방금 만든 두개의 어노테이션 붙여주기

@MyIncludeComponent
public class BeanA {
}
@MyExcludeComponent
public class BeanB{
}

3-3 : 필터를 돌릴 떼



@Configuration
 @ComponentScan(
 includeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
 excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
 )
 static class ComponentFilterAppConfig {
 }
  • includeFilters 에 MyIncludeComponent 애노테이션을 추가해서 BeanA가 스프링 빈에 등록 o
  • excludeFilters 에 MyExcludeComponent 애노테이션을 추가해서 BeanB는 스프링 빈에 등록 x

교재 왈 : 최근 스프링 부트는 컴포넌트 스캔을 기본으로 제공하는데, 개인적으로는 옵션을 변경하면서 사용하기 보다는 스프링의 기본 설정에 최대한 맞추어 사용하는 것을 권장하고, 선호

4. 중복 등록과 충돌

4-1 : 같은 빈 이름을 등록

1. 자동 빈 등록 vs 자동 빈 등록

=> ConflictingBeanDefinitionException 예외가 발생

2. 수동 빈 등록 vs 자동 빈 등록

=> 수동 빈 등록이 우선권
=> 그러나 이런 잠정적인 위험성을 가지고 있는 에러가 더 위험한 법

0개의 댓글