Spring/Spring

[Spring][Core] 3-1. Container: Annotation-based Configuration

noahkim_ 2025. 4. 6. 13:59

1. Using @Autowired

주입 방식

주입 방식 설명 특징
Constructor  생성자를 통해 의존성 주입
✅ 추천 방식 (불변성 보장)
✅ Spring 4.3+에서는 생성자 1개일 경우 @Autowired 생략 가능
Setter setter 메서드를 통해 주입
🔸 선택적 의존성이나 테스트에 유용
🔸 public/protected 접근 필요
Method Argument 일반 메서드에 여러 의존성을 한번에 주입
🔸 구성 로직과 함께 의존성 주입 가능
Field 필드에 직접 주입
🔸 코드 간결
🔸 테스트/DI 프레임워크에서 불편
🔸 private이기 때문에 리플렉션 사용
Mix (혼용) 상황에 따라 적절한 방식 섞어 사용
🔸 가능하지만 혼용은 가독성/유지보수성 저하 가능
🔸 일관된 스타일 권장

 

속성

속성명 기본값 설명 비고
required TRUE 주입할 대상이 없으면 예외 발생 여부 설정
선택적 의존성 주입 시 사용
onConstructor 없음 (자동 감지) 생성자 자동 주입 시 지정할 생성자에 명시적으로 설정 가능
일반적으로 생략
autowireCandidate 빈 등록 시 사용 이 빈이 자동 주입 후보인지 여부 설정 (주입 대상에서 제외 가능)
@Bean 또는 XML에서 설정

 

우선순위

  • 같은 타입의 여러 빈을 주입할 때 우선순위 제어하는 방법
적용 상황 (구분) 사용 방법 비고
순서가 있는 자료구조로 주입받을 때
Ordered 인터페이스 구현
클래스에서 직접 구현
@Order(숫자) 어노테이션 사용
클래스 또는 @Bean 메서드에 사용 가능
@Priority(숫자) 어노테이션 사용
클래스에만 사용 가능 (@Bean 메서드에는 사용 불가)
명세(타입)로 주입받을 때 빈 선택 우선순위 @Primary 어노테이션 사용
@Qualifier로 재정의 가능

 

유의사항

자료구조 타입으로 주입할 경우
자료구조 타입 주입 가능 여부 비고
List<T> ✅ 
등록된 빈들이 주입됨 (순서 보장)
Set<T>
등록된 빈들이 주입됨 (중복 제거, 순서X)
T[] (Array)
배열 형태로 주입됨
Map<String, T>
key는 빈 이름, value는 빈 객체
Map<다른타입, T>
key가 String이 아닐 경우 주입 불가

 

구체 클래스 타입으로 주입할 경우
  • @Bean 메서드의 리턴 타입이 너무 추상적이면 구현체 타입으로는 주입할 수 없음
  • 리턴 타입이 인터페이스라면 구현 클래스 타입으로는 주입이 불가
  • 주입 지점들이 구체 타입을 요구할 가능성이 있다면, @Bean 메서드의 리턴 타입도 구체적으로 설정하는 것이 좋음

 

예시

더보기
@Bean
public KakaoPayService paymentService() {
    return new KakaoPayService();
}
@Autowired
private PaymentService paymentService; // ✅ 주입 가능

@Autowired
private KakaoPayService kakaoPayService; // ✅ 주입 가능

 

Self Injection

  • 자기 자신의 메서드를 프록시를 통해 호출하고 싶을 때 사용함
  • 일반 빈보다 후순위

 

예시

더보기
@Component
public class MyService {
    
    @Autowired
    private MyService self; // ❗자기 자신을 주입

    public void someMethod() {
        self.otherMethod(); // 이건 프록시 기반 기능 (ex. @Transactional)을 사용할 수 있음
    }

    @Transactional
    public void otherMethod() {
        // ...
    }
}
  • @Transaction은 프록시 기반으로 처리됨 (프록시 객체를 통해 메서드 호출될 때만 기능이 적용됨)
  • this.someMethod()는 프록시를 타지 않음
  • 프록시를 타게 하려면 스스로를 주입받아서 호출해야 함

 

2. Fine-tuning Annotation-based Autowiring with Qualifiers

@Qualifier

  • 타입 기반의 @Autowired로 주입받을 때, 주입 대상의 우선순위를 명시하게 해주는 어노테이션
  • 주입 대상이 여러개일 때, 특정 조건이 붙은 빈을 필터링하는데 사용함
  • 빈 등록시 @Qualifier("name")으로 명시한 값으로 비교

 

예제

더보기
@Component
@Qualifier("action")
class ActionMovieCatalog implements MovieCatalog {}

@Component
@Qualifier("action")
class AnotherActionMovieCatalog implements MovieCatalog {}

@Component
class MyService {
    
    // 아래처럼 하면 "action" qualifier가 붙은 것들만 주입됨
    @Autowired
    public MyService(@Qualifier("action") Set<MovieCatalog> catalogs) {
        ...
    }
}

 

3. Using Generics as Autowiring Qualifiers

  • 제네릭 타입을 활용해서 @Autowired 시에 암묵적인 Qualifier 역할을 하게 해주는 기능

 

예제

더보기
@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore(); // implements Store<String>
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore(); // implements Store<Integer>
    }
}
@Autowired
private Store<String> s1; // stringStore() 빈이 주입됨

@Autowired
private Store<Integer> s2; // integerStore() 빈이 주입됨

 

4. Injection with @Resource

항목 설명
소속
JSR-250 (Jakarta EE 표준)
패키지
jakarta.annotation.Resource
대상
필드 or 단일 인자 Setter 메서드
주입 기준 기본값
이름 기반(by-name)
기본 이름 추론
필드 이름 또는 Setter 메서드의 property
이름 생략 시 Fallback
타입 기반(by-type)으로 대체됨
특별한 타입 자동 주입
ApplicationContext, BeanFactory, MessageSource 등은 이름 없이 타입으로 자동 주입됨
(Resolvable Dependency)

 

예제

더보기
@Resource(name="myMovieFinder") 
public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
}
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;

 

5. Using @Value

  • 외부 설정 파일에 정의된 값을 주입 (필드, 생성자, 파라미터)
  • 타입 자동 변환: 문자열 -> Integer, Boolean, String[]

 

예제) @Value

더보기
@Value("${catalog.name}")
private String catalog;
# application.properties
catalog.name=MovieCatalog

 

기본값 설정

@Value("${catalog.name:defaultCatalog}")
private String catalog;
  • ${catalog.name} 값이 없으면 → "defaultCatalog"가 주입됨

 

예제) @PropertySource

더보기
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
  • .properties 파일을 읽어오도록 설정
  • spring boot에서는 자동으로 설정됨

 

ConversionService

  • @Value는 내부적으로 ConversionService를 사용함
  • 직접 Converter를 구현해서 타입 변환에 대한 커스터마이징 가능 

 

예제

더보기
@Bean
public ConversionService conversionService() {
    DefaultFormattingConversionService service = new DefaultFormattingConversionService();
    service.addConverter(new StringToLocalDateConverter());
    return service;
}
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
    @Override
    public LocalDate convert(String source) {
        return LocalDate.parse(source); // ISO 기본 형식 "yyyy-MM-dd" 파싱
    }
}

 

 

항목 DefaultFormattingConversionService
Converter<S, T>
정의 타입 변환과 포매팅을 위한 범용 변환기 서비스 클래스
타입 간 변환을 위한 인터페이스
역할 여러 Converter 및 Formatter들을 등록/관리 및 변환 수행
단일 타입 간의 변환 로직 정의
용도 전체 애플리케이션에서 공통으로 사용할 변환 서비스 제공
커스텀 타입 간 변환 로직 구현
빈 등록 수동 등록 가능
Spring Boot에서는 기본 제공됨
커스텀 구현체를 등록해 사용

 

SpEL

  • #{}을 쓰면 SpEL 문법으로 동적 계산 가능

 

예제

더보기
@Value("#{systemProperties['user.catalog'] + 'Catalog'}")
private String catalog;

 

 

출처