모각소-6(컴포넌트 스캔)

LEEHYUNJE·2024년 1월 28일
0
post-thumbnail

오늘은 김영한 선생님께서 자동 의존관계 주입시스템이 있다고 하셔서 열심히 강의를 들었다. 내용은 다음과 같다.

컴포넌트 스캔

컴포넌트 스캔과 의존관계 자동 주입 시작

  • 지금까지 스프링 빈을 등록할때는 @Bean을 사용하여 스프링 빈을 나열했다.
  • 하지만 실무에서는 많기 때문에 일일이 등록하기 힘들다.
    -> 이를 위해 컴포넌트 스캔이라는 기능을 제공
    -> 의존관계도 자동 주입해주는 @Autowired를 사용한다.
ackage hello.core;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
        excludeFilters =  @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class)
) //애노 테이션이 붙은 것들을 스프링 빈으로 등록시켜준다 // AppConifg를 빼고 등록시키기 위해서 이런짓을 한다.
public class AutoAppConfig {
}
  • 다른 에노테이션 ,Configuration을 빼주기 위해 스프링 빈으로 등록시키지 않는다는 문법이다.

이전에 AppConfig에서는 의존관계를 직접 수정해줘야 했지만, 이번에는 자동으로 의존관계를 주입해준다.

어떻게 작동하는 지 확인해보자.

  • @ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다.
  • 이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.
    • 빈 이름 기본 전략: MemberServiceImpl 클래스 memberServiceImpl
    • 빈 이름 직접 지정: 만약 스프링 빈의 이름을 직접 지정하고 싶으면
  • @Component("memberService2") 이런식으로 이름을 부여하면 된다.

탐색 위치와 기본 스캔 대상

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

@ComponentScan(
        basePackages = "hello.core.member",
        excludeFilters =  @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class)
) //애노 테이션이 붙은 것들을 스프링 빈으로 등록시켜준다 // AppConifg를 빼고 등록시키기 위해서 이런짓을 한다.
public class AutoAppConfig {
}

basePackages 를 통해서 원하는 패키지의 시작위치를 지정할 수 있다.

  • basePackages = {"hello.core", "hello.service"} 이렇게 여러 시작 위치를 지정할 수도
    있다.
  • 지정하지 않으면 @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.

권장하는 방법
개인적으로 즐겨 사용하는 방법은 패키지 위치를 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이다. 최근 스프링 부트도 이 방법을 기본으로 제공한다.

컴포넌트 스캔 기본 대상

컴포넌트 스캔은 @Component 뿐만 아니라 다음과 내용도 추가로 대상에 포함한다.

  • @Component : 컴포넌트 스캔에서 사용
  • @Controller : 스프링 MVC 컨트롤러에서 사용
  • @Service : 스프링 비즈니스 로직에서 사용
  • @Repository : 스프링 데이터 접근 계층에서 사용 -> jpa
  • @Configuration : 스프링 설정 정보에서 사용

참고 : 에노테이션에는 상속 관계라는 것이 없다. 애노테이션이 특정 애노테이션을 들고 있는 것을 인식할 수 있는 것은 spring이 해주는 것 이다.

컴포넌트 스캔의 용도 뿐만 아니라 다음 애노테이션이 있으면 스프링은 부가 기능을 수행한다.

  • @Controller : 스프링 MVC 컨트롤러로 인식
  • @Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
  • @Configuration : 앞서 보았듯이 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리
    를 한다.
  • @Service : 사실 @Service 는 특별한 처리를 하지 않는다. 대신 개발자들이 핵심 비즈니스 로직이 여기에 있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.

참고: useDefaultFilters 옵션은 기본으로 켜져있는데, 이 옵션을 끄면 기본 스캔 대상들이 제외된다. 이런 옵션이 있다고만 알고 있자.

필터

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
  • excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.
  @Configuration
    @ComponentScan(
            includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
            excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
    )

FilterType 옵션

  • ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
    ex) org.example.SomeAnnotation
  • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
    ex) org.example.SomeClass
  • ASPECTJ: AspectJ 패턴 사용
    ex) org.example..*Service+
  • REGEX: 정규 표현식
    ex) org.example.Default.*
  • CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리
    ex) org.example.MyTypeFilter
@ComponentScan(
 includeFilters = {
 @Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
 },
 excludeFilters = {
 @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class),
 @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BeanA.class)
 }
)
  • 요즘은 includeFilter은 사용할 일이 거의 없다. excludeFilters는 여러가지 이유로 간혹사용할 때가 있다.

중복 등록과 충돌

  1. 자동 빈 등록 vs 자동 빈 등록
  2. 수동 빈 등록 vs 자동 빈 등록 - > 자주 일어난다.

자동 빈 등록 vs 자동 빈 등록

  • 컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
    • ConflictingBeanDefinitionException 예외 발생

오류메세지만 잘 보면 spring 에러는 다 잡을 수 있다.

수동 빈 등록 vs 자동 빈 등록

@Configuration
@ComponentScan(
 excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class)
)
public class AutoAppConfig {
 @Bean(name = "memoryMemberRepository")
 public MemberRepository memberRepository() {
 return new MemoryMemberRepository();
 }
}

수동 빈이 자동 빈보다 우선권을 가진다.
(수동 빈이 자동 빈을 오버라이딩 해버린다.)

  • 하지만 최근 스프링 부트에서는 수동 빈과 자동 빈이 충돌하면 팅겨버리게 만들었다.

"어설픈 추상화, 어설픈 우선순위 보다는 명확하게 코드를 쓰거나, 빨리 오류가 나서 팅기는게 좋다." - 김영한 강사님

모각소 소감

오늘은 자동의존관계 주입에 대해서 공부했다. 계속해서 느끼는데, 그냥 스프링 컨테이너에 넣어서 사용하는 방법만 지금 2주동안 공부하는 느낌이다. 실질적인 개발을 원하는데 점점 이론에 지쳐가는 느낌이지만, 기본기가 가장 중요한 것이므로 참고 열심히해보자. 같이 모각소하는 팀원들이 앞으로도 팀프로젝트를 같이할 팀원들이여서 더 열심히 하게되는 것 같다. 모각소 앞으로도 애용해보자. 애옹


출처: 김영한 강사님의
스프링 핵심 원리 - 기본편

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

profile
현재진행중

0개의 댓글