본문 바로가기

back-end/spring

spring/ 컴포넌트 스캔

@Component와 @Autowired를 통한 컴포넌트 스캔

 

클래스 레벨에 @Configuration을 붙여 스프링 컨테이너에 구성 정보를 제공하고, 각 메서드마다 @Bean을 붙여 스프링 빈을 등록하는 방식은 등록해야 할 빈이 많아지면 효율적이지 못한 문제가 있다.

 

이를 해결하는 방법은 설정 정보 없이도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔 기능과 의존 관계를 자동으로 주입해주는 @Autowired 기능을 사용하는 것이다.

 

컴포넌트 스캔은 기존의 방식과는 다르게 @Component 가 붙은 클래스를 스캔해 스프링 빈으로 등록한다.

 

추가로, @Controller, @Repository, @Configuration 역시 스캔 대상에 포함하고 각각 MVC 컨트롤러, 스프링 데이터 접근 계층, 스프링 설정 정보로 인식한다. 추가로 @Service 역시 인식하는데 특별한 처리를 하지는 않고 개발자 측에서 비즈니스 계층으로 인식하는 데 도움이 된다.

 

 

 

대략적으로 위와 같은 프로그램을 설계한다고 가정한다.

 

일단 인터페이스를 구현하고 있는 실제로 사용할 클래스에 @Componet를 붙여 컴포넌트 스캔의 대상으로 등록한다. 여기서는 MemoryMemberRepository와 FixPointPolicy 클래스를 사용한다고 가정한다.

 

@Component
public class MemoryMemberRepository implements MemberRepository {...}

 

@Component
public class FixPointPolicy implements PointPolicy {...}

 

 

이어서 MemberService와 OrderService를 구현하는 MemberServiceImpl 클래스와 OrderServiceImple 역시 @Component를 사용해 등록하고, @Autowired로 의존 관계를 주입한다.

 

@Component
public class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository;
	
    @Autowired //의존 관계 자동 주입
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void register(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

 

@Component
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final PointPolicy pointPolicy;
	
    @Autowired //의존 관계 자동 주입
    public OrderServiceImpl(MemberRepository memberRepository, PointPolicy pointPolicy) {
        this.memberRepository = memberRepository;
        this.pointPolicy = pointPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int point = pointPolicy.point(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, point);
    }
}

 


필터를 사용해 컴포넌트 스캔 대상을 지정하기

 

@ComonentScan을 사용할 때 옵션으로 includeFiltersexcludeFilters를 사용해서 스캔에 포함하거나 제외할 클래스를 지정할 수 있다.

 

필터 적용을 위해 자체적으로 어노테이션을 만든다. 만든 어노테이션을 포함하거나 제외할 클래스 레벨에 붙이고,  컴포넌트 스캔 포함/제외 대상을 지정한다.

 

excludeFilters 사용 예

1. 어노테이션 생성

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

 

2. 클래스에 어노테이션 적용

@ExcludeComponent
public class ExcludeBean {}

 

3. @ComponentScan 시 적용

import static org.springframework.context.annotation.ComponentScan.*;

@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = ExcludeBean.class)

 


 

FilterType의 옵션

ANNOTATION

기본 값으로, 어노테이션을 인식해 동작한다.

ASSIGNABLE_TYPE

지정한 타입 및 자식 타입을 인식해 동작한다.

ASPECTJ

AspectJ 패턴을 사용한다.

REGEX

정규표현식

CUSTOM

TypeFilter라는 인터페이스를 구현해서 처리한다.