본문 바로가기

Back-End/Spring

Spring Bean 등록

@ComponentScan

Spring이 특정 패키지 내에서 @Component, @Service, @Repository, @Controller 같은 애노테이션이 붙은 클래스를 자동으로 검색하고, 이를 Bean으로 등록하는 기능이다. 개발자가 Bean을 직접 등록하지 않고도 Spring이 자동으로 관리할 객체를 찾는다.

  • ComponentScan의 범위 
    • basePackages : 특정 패키지를 스캔할 때 사용, 배열로 여러 개를 선언
      • ex) @ComponentScan(basePackages = {"com.example", "com.another"})
    • basePakageClasses : 특정 클래스가 속한 패키지를 기준으로 스캔할 수 있다.
      • ex) @ComponentScan(basePackageClasses = MyApp.class)
    • excludeFilters : 스캔에서 제외할 클래스를 필터링할 수 있다.
      • ex) @ComponentScan(excludeFilters = @ComponentScan.Filter(SomeClass.class))
    • includeFilters : 특정 조건에 맞는 클래스만 스캔하여 포함할 수 있다.
      • ex) @ComponentScan(includeFilters = @ComponentScan.Filter(Service.class))
  • ComponentScan의 동작 순서
    1. Spring Application이 실행되면 @ComponentScan이 지정된 패키지를 탐색한다.
    2. 해당 패키지에서 @Component 또는 애노테이션이 붙은 클래스를 찾는다.
    3. 찾은 클래스를 Spring 컨테이너에 빈으로 등록한다.
    4. 등록된 빈은 DI과 같은 방식으로 다른 빈과 연결 된다.

Spring Bean 자동 등록 방법

  • @component를 클래스에 위에 작성하면 된다.

Spring Bean 수동 등록 방법

  • @Configuration이 있는 클래스를 빈으로 등록하고 해당 클래스를 파싱해서 @Bean이 있는 메서드를 찾아 Bean을 생성한다.
    참고로 수동으로 Bean을 등록할 때는 항상 @Configuration과 함께 사용해야 Bean이 싱글톤으로 관리된다.
// 인터페이스
public interface TestService {
    void doSomething();
}

// 인터페이스 구현체
public class TestServiceImpl implements TestService {
    @Override
    public void doSomething() {
        System.out.println("Test Service 메서드 호출");
    }
}

// 수동으로 빈 등록
@Configuration
public class AppConfig {
    
    // TestService 타입의 Spring Bean 등록
    @Bean
    public TestService testService() {
        // TestServiceImpl을 Bean으로 등록
        return new TestServiceImpl();
    }
    
}

// Spring Bean으로 등록이 되었는지 확인
public class MainApp {
    public static void main(String[] args) {
        // Spring ApplicationContext 생성 및 설정 클래스(AppConfig) 등록
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 등록된 TestService 빈 가져오기
        TestService service = context.getBean(TestService.class);

        // 빈 메서드 호출
        service.doSomething();
    }
}

같은 타입의 Bean이 충돌할 때

1. @Qualifier 
@Qualifier명시적으로 어떤 bean을 사용할지 지정할 수 있도록 도와준다.

  • 특정 Bean을 지정해야 할 때
  • Bean 이름을 기반으로 명확하게 구분해야 할 때
@Component
@Qualifier("firstService")
public class MyServiceImplV1 implements MyService { ... }

@Component
@Qualifier("secondService")
public class MyServiceImplV2 implements MyService { ... }

@Component
public class ConflictApp {

    private final MyService myService;

    @Autowired
    public ConflictApp(@Qualifier("firstService") MyService myService) {
        this.myService = myService;
    }
}

2. @Primary
@Primary우선 순위를 부여하여 충돌 시 기본으로 선택되도록 설정한다.

  • 주로 사용해야 할 Bean이 정해져 있을 때
  • 디폴트 Bean을 설정해야 할 때
    참고) @Primary와 @Qualifier가 동시에 사용될 경우 @Qualifier 우선순위가 더 높다
@Component
@Primary
public class MyServiceImplV2 implements MyService { ... }

@Component
public class ConflictApp {

    private final MyService myService;

    @Autowired
    public ConflictApp(MyService myService) {
        // MyServiceImplV2가 기본으로 주입됨
        this.myService = myService;
    }
}

3. Custom Annotation 
사용자 정의 애노테이션을 만들어 특정 Bean을 구분하는 방법

  • 복잡한 프로젝트에서 Bean을 그룹으로 관리하고 싶을 때
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface FirstService {
}

@Component
@FirstService
public class MyServiceImplV1 implements MyService { ... }

@Component
public class ConflictApp {

    private final MyService myService;

    @Autowired
    public ConflictApp(@FirstService MyService myService) {
        this.myService = myService;
    }
}

그럼 자동 Bean 등록을 사용? 수동 Bean 등록을 사용?

1. 대부분의 경우 자동으로 Bean을 등록

  • 자동 등록이 더 간편하고 현대적인 방식이다.
  • 예외적으로 충돌 관리가 필요한 경우 @Qualifier나 @Primary를 활용

2. 특별한 요구사항이 있을 경우 수동으로 Bean을 등록

  • 특정한 초기화 로직이나 의존성 관계가 복잡한 경우에는 수동 등록이 유리하다.
  • 예를 들어, 외부 라이브러리나 커스텀 객체를 Bean으로 등록해야 한다면 Config를 사용하자

'Back-End > Spring' 카테고리의 다른 글

스프링 트랜잭션의 이해(feat. 전파)  (0) 2025.01.20
Spring Valid  (1) 2024.12.08
IOC / DI  (0) 2024.12.06
Spring Container와 Spring Bean  (0) 2024.12.06
객체 지향 설계(SOLID 원칙)  (1) 2024.12.06