스프링 기본 section 7

Sean·2025년 5월 8일

컴포넌트 스캔

지금까지는 스프링 빈 등록시, @Bean, <bean> 으로 설정 정보 등록함.
-> 문제 : 스프링 빈 수 늘어날수록 할 일 너무 많아짐.
-> 해결 : 설정정보 없이 자동으로 빈 등록하는 컴포넌트 스캔 기능 제공.

컴포넌트 스캔 적용
@Configuration
@ComponentScan(
	excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class))
public class AutoAppConfig {
	
}
  • @ComponentScan 붙여주면 됨.
  • 기존과 달리, @Bean등록한 클래스 없음.

스캔 대상 : @Component 붙은 클래스

@Component
public class MemoryMemberRepository implements MemberRepository {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class MemberServiceImpl implements MemberService {
	private final MemberRepository memberRepository;

	@Autowired
	public MemberServiceImpl(MemberRepository memberRepository) {
		this.memberRepository = memberRepository;
	}
}

설정정보 작성 없어져 편해짐. 근데 의존관계 명시까지 없어짐.
-> 의존관계 주입 시켜주자.
-> 생성자에 @Autowired

@Component
public class OrderServiceImpl implements OrderService {
	private final MemberRepository memberRepository;
	private final DiscountPolicy discountPolicy;

	@Autowired
	public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
		this.memberRepository = memberRepository;
		this.discountPolicy = discountPolicy;
	}
}

  1. @ComponentScan
  • 빈 이름 기본 전략 : MemberServiceImpl -> memberServiceImpl ( 앞만 소문자로 )
  • 빈 이름 직접 지정 : `@Component("memberService2")``
  1. @Autowired 의존관계 자동 주입
  • @Autowired 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈 찾아서 주입.
  • 기본 조회 전략 : 타입이 같은 빈 찾아서 주입
  • 파라미터 많아도 문제 X.

Q. @Autowired 없어도 되지 않나? 어차피 생성자에 의존관계 적혀있으니까.

A. 실제로 @Autowired 없이도 의존관계 주입됨. 스프링 4.3 이후로 가능해졌음. 대신 생성자가 하나만 있을 경우에만 가능. 생성자가 두 개 이상일시, @Autowired 붙은 생성자만 의존관계 주입됨. ( 실무에서는 생성자를 두 개 이상 쓸 일 잘 없긴 함 )

탐색 위치와 기본 스캔 대상

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

모든 자바클래스 컴포넌트 스캔 하려면 시간 오래걸림. 꼭 필요한 위치부터 탐색하도록 시작 위치 지정 가능.

@ComponentScan(
	basePackages = "hello.core",
}
  • basePackages: 탐색할 패키지 시작 위치 지정. 이 패키지 포함 하위 패키지 탐색함.

권장 방법

패키지 위치 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것.
스프링 부트도 이 방법을 기본으로 제공함.

  • 스프링부트 사용하면 @SpringBootApplication 프로젝트 위치에 두는 관례. ( 이 설정정보 안에 @ComponentScan 들어있음 )

컴포넌트 스캔 기본 대상

@Component 뿐만 아니라 해당 것들도 스캔 대상.
-> @Controller, @Service, @Repository, @Configuration

@Component
public @interface Controller {
}

@Component
public @interface Service {
}

@Component
public @interface Configuration {
}

-> 소스코드 확인시, @Component 포함 확인
가능.


필터

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정
  • excludeFilters : 컴포넌트 스캔에서 제외할 대상 지정
1. 어노테이션 생성
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {}
2. 어노테이션 클래스에 적용
@MyIncludeComponent
public class BeanA {}

@MyExcludeComponent
public class BeanB {}
3. 필터 적용한 AppConfig
@Configuration
@ComponentScan(
	includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyInlcudeComponent.class),
    excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
public class AppConfig {}

중복 등록과 충돌

컴포넌트 스캔에서 같은 빈 이름 등록하면 어떻게 될까.

  1. 자동 빈 등록 - 자동 빈 등록
  2. 수동 빈 등록 - 자동 빈 등록

1. 자동 빈 등록 - 자동 빈 등록

  • ConflictingBeanDefinitionException 예외 발생

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

자동 빈
@Component
public class MemoryMemberRepository implements MemberRepository {}
수동 빈
@Configuration
@ComponentScan(
	excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class)
)
public class AutoAppConfig {

	@Bean(name = "memoryMemberRepository")
	public MemberRepository memberRepository() {
		return new MemoryMemberRepository();
	}
}
  • 에러 X
  • 수동 빈 등록이 우선권 가짐. ( 수동 빈이 자동 빈을 오버라이딩 )

의도한 행동이라면 괜챃지만, 보통 설정 꼬여서 상황 발생함. -> 정말 잡기 어려운 버그 발생.
-> 최근 스프링 부트에서는 오류 발생하도록 바뀜.

profile
저스트두잇

0개의 댓글