본문 바로가기

[Spring] @ComponentScan , @AutoWired - 자동 Bean 등록

@xuv22025. 6. 16. 20:45

스프링 컨테이너에 스프링 빈을 등록하는 가장 원초적이고 직관적인 방법은 @Bean 에노테이션을 활용하는 것이다.

하지만 서비스가 커지면 커질 수록 몇백개, 몇천개로 늘어나는 빈을 일일히 등록하고 관리하는 것은 쉽지 않다.

스프링은 이런 귀차니즘을 해소하기 위해 설정 정보 없이 스프링 빈을 자동으로 등록해주는 컴포넌트 스캔이라는 기능을 제공하고, 의존 관계를 자동으로 주입해주는 @Autowired 라는 에노테이션도 제공한다.


컴포넌트 스캔 사용 예시

@ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다.

 

@ComponentScan

컴포넌트 스캔을 사용하기 위해선 먼저 @ComponentScan 에노테이션을 붙여주면 된다.

import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
//        basePackages = "hello.core",
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) // AppConfig, TestConfig 등을 제외하기 위해 필터링
)
public class AutoAppConfig {

}

예시에서 필터는 기존에 작성했던 Config 파일들도 같이 빈으로 등록되는것을 방지하기 위해 설정해두었다.

 

@Component

이후 사용하고자 하는 클래스에 @Component 에노테이션을 붙여준다.

@Component // rateDiscountPolicy 라는 이름으로 컴포넌트 스캔시 자동 생성 됨
public class RateDiscountPolicy implements DiscountPolicy {}

@Component // memoryMemberRepository 라는 이름으로 컴포넌트 스캔시 자동 생성 됨
public class MemoryMemberRepository implements MemberRepository{}

 

@ComponentScan + @AutoWired

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MemberServiceImpl implements MemberService {

    // 회원 가입 + 회원 조회
    private final MemberRepository memberRepository;

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

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

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

    // 테스트용
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }

}

@AutoWired 에노테이션이 붙어있으면, 스프링이 알아서 생성자에 알맞는 구현체를 DI 해준다.

주입 받아야할 대상이 여러개여도 한번에 주입 가능!


테스트 코드 작성

import hello.core.AutoAppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


import static org.assertj.core.api.Assertions.*;

public class AutoAppConfigTest {

    @Test
    void basicScan() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberService.class); // 이름 같으면 오류 발생
    }
}

자동 등록된 빈이 쭉 뜨는 것을 확인할 수 있다.

만약 로그가 위와 같이 뜨지 않고 싸가지 없이 결과 값만 뜬다면 다음 글을 확인하자.

https://bdisappointed.tistory.com/138

 

[Spring] 며칠 굶은 것 같이 부실한 로그

로그가 밥을 덜먹었나..스프링부트 3.1 버전부터는 스프링 빈을 출력하는 로그가 대폭 생략되었다.예를들어 아래처럼 컴포넌트 스캔한 빈들을 조회하고자 할때 3.1 버전 부턴 다음과 같이 간소화

bdisappointed.tistory.com


 

컴포넌트 스캔 대상

@Component(basePackages = "") 라는 옵션 파라미터를 통해 탐색을 시작할 위치를 지정할 수 있다.

모든 자바 클래스를 다 컴포넌트 스캔하면 시간이 너무 오래 걸리기에, 꼭 필요한 위치에 삽입하여 시작 위치를 설정해야한다.

보편적인 방법으로는 옵션을 사용하기 보단, Configuration 클래스 파일을 프로젝트 최상단에 두면 다음과 같이 컴포넌트 스캔이 실행된다.

com. hello 에서 @Component 실행 -> com.hello.service, com.hello.repository.....com.hello.*

여담으로 메인 클래스인 @SpringBootApplication 에노테이션도 사실 @ComponentScan이 들어있다.

 

컴포넌트 스캔 기본 대상

@Controller, @Service, @Repository, @Configuration 등 스프링 비즈니스 로직에서 사용되는 에노테이션들은 대부분 @ComponentScan 에노테이션을 포함하고 있다.

xuv2
@xuv2 :: xuvlog

폭싹 늙었수다

목차