본문 바로가기
Spring Study

어노테이션 기반의 Spring 컨테이너 구성

by xogns93 2024. 9. 4.
어노테이션 기반의 Spring 컨테이너 구성

 

Spring Framework의 @Autowired 어노테이션

 

1. @Autowired 어노테이션의 개요

@Autowired 어노테이션은 Spring에서 의존성 주입(Dependency Injection)을 처리하는 중요한 도구입니다. 이 어노테이션은 필드, 메서드, 생성자에 붙여 사용되며, Spring 컨테이너가 관리하는 빈(bean) 중에서 해당 타입의 빈을 자동으로 주입하게 됩니다.
 

2. @Autowired 어노테이션 사용 예시

2.1. 생성자 주입(Constructor Injection)

@Component
public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
}
  • 이 코드에서 MovieRecommender 클래스는 CustomerPreferenceDao라는 의존성을 생성자를 통해 주입받습니다.
  • Spring 4.3 이후, 클래스에 생성자가 하나만 있을 경우 @Autowired를 생략해도 됩니다. 그러나 여러 생성자가 있을 경우, Spring이 어느 생성자를 사용할지 알 수 있도록 하나 이상의 생성자에 @Autowired를 지정해야 합니다.
     

2.2. 세터 주입(Setter Injection)

@Component
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
  • setMovieFinder 메서드에 @Autowired를 붙여, Spring이 해당 메서드를 통해 MovieFinder 빈을 주입합니다.
  • 이는 전통적인 세터 주입 방식으로, 메서드 이름과 상관없이 주입할 수 있습니다.
     

2.3. 메서드 주입(Method Injection) - 복수 인자 지원

@Component
public class MovieRecommender {

    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
}
  • prepare 메서드처럼 여러 인자를 가진 메서드에 @Autowired를 사용해 복수의 의존성을 주입할 수 있습니다.
     

2.4. 필드 주입(Field Injection)

@Component
public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
}
  • 필드에 직접 @Autowired를 붙여 주입할 수도 있습니다. 필드 주입은 간편하지만, 테스트가 어렵고, 클래스가 Spring에 강하게 결합된다는 단점이 있습니다.
     

3. 특수한 상황에서의 @Autowired 사용

3.1. 배열 및 컬렉션 타입의 주입

@Component
public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;
}
@Component
public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }
}
  • 배열이나 컬렉션 형태로 여러 빈을 주입받을 수 있습니다. 이때, MovieCatalog 타입의 모든 빈이 주입됩니다.
  • 이러한 주입에서 @Order@Priority를 사용하여 배열이나 컬렉션의 순서를 지정할 수도 있습니다.
     

3.2. 맵(Map) 타입의 주입

@Component
public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }
}
  • Map 형태로 주입받을 수도 있습니다. 이 경우, 키는 빈의 이름(String), 값은 해당 타입의 빈이 됩니다.
  • 이러한 방법은 각 빈에 이름을 붙여 관리할 때 유용합니다.
     

4. 선택적 의존성 주입

4.1. @Autowired(required = false)

@Component
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required = false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
  • @Autowiredrequired 속성을 false로 설정하면, 해당 빈이 없어도 애플리케이션이 정상적으로 동작할 수 있도록 할 수 있습니다.
  • 이 옵션을 통해 선택적으로 의존성을 주입받을 수 있습니다.
     

4.2. Optional 사용

@Component
public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(Optional<MovieFinder> movieFinder) {
        // ...
    }
}
  • Java 8의 Optional을 사용하여, 주입받을 빈이 선택적임을 명시적으로 표현할 수 있습니다.
     

4.3. @Nullable 사용

@Component
public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        // ...
    }
}
  • @Nullable 어노테이션을 사용하여, 해당 의존성이 없을 때 null 값이 주입되도록 할 수 있습니다. 이는 선택적 의존성을 처리하는 또 다른 방법입니다.
     

5. 특별한 타입의 자동 주입

@Component
public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }
}
  • ApplicationContext, BeanFactory, Environment 등의 Spring 내장 인터페이스들도 자동 주입이 가능합니다.
  • 이러한 인터페이스들은 Spring의 내부 동작에 깊이 관여하므로, 특별한 설정 없이도 자동으로 주입됩니다.
     

 

@Primary 어노테이션을 사용한 Spring의 자동 주입 세밀 조정

 

1. @Primary 어노테이션의 필요성

Spring에서 의존성 주입을 할 때, 같은 타입의 빈이 여러 개 있을 경우 어떤 빈을 주입할지 결정해야 하는 상황이 발생할 수 있습니다. 기본적으로, Spring은 타입 기반으로 자동 주입을 시도하지만, 여러 후보가 있는 경우에는 특정한 빈을 우선적으로 주입할 방법이 필요합니다. 이때 사용하는 것이 바로 @Primary 어노테이션입니다.

@Primary 어노테이션은 여러 후보 빈 중에서 특정 빈을 우선적으로 선택하게 만듭니다. 만약 여러 빈 중에 하나의 @Primary 빈이 존재한다면, 해당 빈이 자동으로 주입됩니다.
 

2. @Primary 어노테이션의 사용 예시

다음은 @Primary 어노테이션을 사용하여 두 개의 MovieCatalog 빈 중 첫 번째 빈을 우선적으로 주입하는 예제입니다.
 

2.1. 자바 설정(Java Configuration) 예제

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() {
        // 첫 번째 MovieCatalog 빈 설정
        return new FirstMovieCatalog();
    }

    @Bean
    public MovieCatalog secondMovieCatalog() {
        // 두 번째 MovieCatalog 빈 설정
        return new SecondMovieCatalog();
    }
}
  • MovieConfiguration 클래스에서 firstMovieCatalog 빈이 @Primary로 지정되었습니다.
  • 이 설정에 따라, MovieCatalog 타입의 빈을 자동 주입할 때, Spring은 firstMovieCatalog를 우선적으로 선택합니다.
     

2.2. @Primary를 사용한 자동 주입

@Primary로 설정된 빈이 실제로 어떻게 주입되는지 확인해보겠습니다.

@Component
public class MovieRecommender {

    @Autowired
    private MovieCatalog movieCatalog;

    // ...
}
  • MovieRecommender 클래스에서 MovieCatalog 타입의 빈이 주입됩니다.
  • 이때, MovieCatalog 빈 중 @Primary로 지정된 firstMovieCatalog가 주입됩니다.
     

2.3. XML 설정(XML Configuration) 예제

Spring에서 XML을 사용하여 빈을 정의하는 경우에도 @Primary와 같은 기능을 사용할 수 있습니다. 다음은 XML 설정 예제입니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- 해당 빈이 주입될 때 우선적으로 사용됨 -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- 이 빈은 기본적으로 주입되지 않음 -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
  • 첫 번째 SimpleMovieCatalog 빈이 primary="true"로 설정되어 있어, 주입 시 이 빈이 우선 선택됩니다.
  • 두 번째 SimpleMovieCatalog 빈은 주입 시 선택되지 않습니다.
  • movieRecommender 빈은 @AutowiredMovieCatalog 빈을 주입받을 때 첫 번째 SimpleMovieCatalog를 주입받게 됩니다.
     

 

@Qualifier 어노테이션을 사용한 Spring의 자동 주입 세밀 조정

 

1. @Qualifier 어노테이션의 필요성

@Primary 어노테이션은 여러 빈 중 하나를 우선적으로 주입할 때 유용하지만, 특정 상황에서는 더 세밀한 제어가 필요할 수 있습니다. 이때 사용하는 것이 바로 @Qualifier 어노테이션입니다. @Qualifier는 특정 빈을 선택하는 데 필요한 추가적인 정보를 제공하여, 동일한 타입의 여러 빈 중에서 정확히 어떤 빈을 주입할지 명확하게 지정할 수 있게 합니다.
 

2. @Qualifier 어노테이션의 사용 예시

2.1. 필드에 @Qualifier 사용

가장 기본적인 예로, @Qualifier를 필드에 직접 적용하여 특정 빈을 주입할 수 있습니다.

@Component
public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...
}
  • 이 예제에서 MovieCatalog 타입의 빈 중에서 main이라는 이름의 빈이 주입됩니다.
  • @Qualifier("main")을 사용하여 주입할 빈을 명확히 지정할 수 있습니다.
     

2.2. 메서드 인자에 @Qualifier 사용

@Qualifier는 생성자나 메서드의 인자에도 적용할 수 있습니다.

@Component
public class MovieRecommender {

    private final MovieCatalog movieCatalog;
    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}
  • prepare 메서드에서 MovieCatalog 타입의 빈 중에서 main이라는 이름의 빈이 주입되도록 지정합니다.
  • 다른 인자 CustomerPreferenceDao는 타입에 따라 자동으로 주입됩니다.
     

2.3. XML 설정에서의 @Qualifier 사용

Spring XML 설정에서도 @Qualifier와 같은 효과를 낼 수 있습니다. 다음은 XML 설정 예제입니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/> 
        <!-- 필요한 의존성 주입 -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/> 
        <!-- 필요한 의존성 주입 -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
  • mainaction이라는 qualifier 값을 가진 두 개의 SimpleMovieCatalog 빈이 정의되어 있습니다.
  • movieRecommender 빈에서 main 또는 action이라는 qualifier 값을 통해 특정 빈을 주입받을 수 있습니다.
     

2.4. 컬렉션과 @Qualifier 사용

@Qualifier를 사용하여 여러 빈을 컬렉션으로 주입받을 수도 있습니다.

@Component
public class MovieRecommender {

    private Set<MovieCatalog> actionCatalogs;

    @Autowired
    public void setActionCatalogs(@Qualifier("action") Set<MovieCatalog> actionCatalogs) {
        this.actionCatalogs = actionCatalogs;
    }

    // ...
}
  • 여러 MovieCatalog 빈이 action이라는 qualifier 값을 가지고 있다면, 이 빈들이 모두 Set<MovieCatalog>에 주입됩니다.
     

2.5. 커스텀 @Qualifier 어노테이션 사용

자신만의 커스텀 @Qualifier 어노테이션을 정의하여 사용할 수도 있습니다.

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
    String value();
}
@Component
public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;

    @Autowired
    @Genre("Comedy")
    private MovieCatalog comedyCatalog;

    // ...
}
  • @Genre라는 커스텀 어노테이션을 정의하여, 특정 장르의 MovieCatalog 빈을 주입받도록 설정할 수 있습니다.
  • XML 설정에서 이 커스텀 어노테이션을 사용하여 빈을 정의할 수도 있습니다.
    <bean class="example.SimpleMovieCatalog">
      <qualifier type="Genre" value="Action"/>
      <!-- 필요한 의존성 주입 -->
    </bean>
    

```  


 

제네릭을 활용한 Spring의 자동 주입 세밀 조정

 
Spring Framework에서 제네릭(Generic) 타입을 사용하여 자동 주입 시 빈을 구분하는 방법에 대해 설명드리겠습니다. 제네릭을 사용하면 @Qualifier 어노테이션 없이도 특정 타입의 빈을 선택할 수 있습니다.
 

1. 제네릭을 사용한 자동 주입의 개요

Spring에서는 제네릭 타입을 사용하여 자동 주입 시 특정 빈을 구분할 수 있습니다. 이는 @Qualifier를 사용하는 대신, 제네릭 타입 자체가 빈을 구분하는 역할을 합니다. 이 방법을 사용하면 코드를 더 간결하게 작성할 수 있으며, 제네릭 타입 정보를 활용하여 더욱 세밀하게 빈을 관리할 수 있습니다.
 

2. 제네릭을 사용한 자동 주입의 예시

다음은 제네릭 타입을 사용하여 빈을 구분하고 주입하는 예제입니다.

2.1. 빈 설정

먼저, 제네릭 인터페이스를 구현하는 두 개의 빈을 설정해 보겠습니다.

@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }
}
  • StringStoreStore<String>을 구현하고, IntegerStoreStore<Integer>를 구현합니다.
  • 이 두 빈은 각각 제네릭 타입에 따라 구분됩니다.
     

2.2. 제네릭을 사용한 빈 주입

이제, Store<String>Store<Integer> 타입의 빈을 주입하는 코드를 살펴보겠습니다.

@Component
public class MyService {

    @Autowired
    private Store<String> s1; // <String> 타입의 Store 빈 주입 (stringStore 빈)

    @Autowired
    private Store<Integer> s2; // <Integer> 타입의 Store 빈 주입 (integerStore 빈)
}
  • s1 필드는 Store<String> 타입의 빈을 주입받으며, 이는 stringStore 빈입니다.
  • s2 필드는 Store<Integer> 타입의 빈을 주입받으며, 이는 integerStore 빈입니다.
  • 제네릭 타입이 자동으로 @Qualifier와 같은 역할을 하여 적절한 빈을 선택합니다.
     

2.3. 제네릭을 사용한 컬렉션 주입

Spring은 제네릭 타입을 사용하여 컬렉션도 주입할 수 있습니다. 예를 들어, 특정 제네릭 타입을 가진 모든 빈을 리스트(List)로 주입할 수 있습니다.

@Component
public class MyService {

    @Autowired
    private List<Store<Integer>> s; // <Integer> 타입의 Store 빈들만 주입
}
  • List<Store<Integer>> 타입의 필드 s에는 Store<Integer> 타입의 모든 빈이 주입됩니다.
  • Store<String> 타입의 빈은 이 리스트에 포함되지 않습니다.
  • 이렇게 제네릭을 사용하면 여러 빈을 쉽게 그룹화하여 관리할 수 있습니다.
     

 

CustomAutowireConfigurer를 사용한 커스텀 자동 주입 구성

 
Spring Framework에서 CustomAutowireConfigurer를 사용하여 커스텀 자동 주입(Autowiring)을 설정하는 방법에 대해 살펴보겠습니다. CustomAutowireConfigurer는 Spring의 @Qualifier 어노테이션을 사용하지 않고도 커스텀 어노테이션을 활용해 자동 주입을 설정할 수 있는 유용한 도구입니다.
 

1. CustomAutowireConfigurer 개요

CustomAutowireConfigurer는 Spring의 BeanFactoryPostProcessor 중 하나로, 커스텀 어노테이션을 사용해 의존성 주입 시 후보 빈을 결정할 수 있게 해줍니다. 이 기능은 Spring의 @Qualifier 어노테이션을 확장하여, 커스텀 어노테이션을 사용해 보다 유연한 의존성 주입을 가능하게 합니다.
 

2. CustomAutowireConfigurer 설정 예시

먼저, CustomAutowireConfigurer를 사용하여 커스텀 어노테이션을 등록하는 방법을 살펴보겠습니다.

2.1. XML 설정에서 CustomAutowireConfigurer 사용

다음은 XML 설정에서 CustomAutowireConfigurer를 사용하여 커스텀 어노테이션을 등록하는 방법을 보여줍니다.

<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>
  • customAutowireConfigurer 빈은 CustomAutowireConfigurer 클래스를 사용하여 정의됩니다.
  • customQualifierTypes 속성에 CustomQualifier라는 커스텀 어노테이션을 등록하여, 이 어노테이션을 사용해 자동 주입을 설정할 수 있도록 합니다.
     

2.2. 커스텀 어노테이션 정의

이제, XML 설정에서 사용된 CustomQualifier라는 커스텀 어노테이션을 정의해보겠습니다.

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomQualifier {
    String value();
}
  • CustomQualifier는 필드나 메서드 파라미터에 적용될 수 있는 커스텀 어노테이션입니다.
  • 이 어노테이션은 value 속성을 가지고 있으며, 이를 통해 특정 빈을 지정할 수 있습니다.
     

2.3. CustomQualifier를 사용한 자동 주입

커스텀 어노테이션을 사용하여 특정 빈을 주입하는 방법을 살펴보겠습니다.

@Component
public class MyService {

    @Autowired
    @CustomQualifier("special")
    private MyRepository myRepository;

    // ...
}
  • MyService 클래스에서 MyRepository 타입의 빈을 주입받을 때, @CustomQualifier("special") 어노테이션을 사용하여 특정한 MyRepository 빈을 주입받습니다.
     

3. 자동 주입 후보 결정

Spring의 AutowireCandidateResolver는 자동 주입 후보를 결정할 때 다음과 같은 요소를 고려합니다:

  1. autowire-candidate 속성: 각 빈 정의에서 이 값이 true로 설정된 빈만 주입 후보가 됩니다.
  2. default-autowire-candidates 패턴: <beans/> 요소에 설정된 기본 패턴에 따라 후보가 결정됩니다.
  3. @Qualifier 어노테이션과 커스텀 어노테이션: @Qualifier 또는 CustomAutowireConfigurer에 등록된 커스텀 어노테이션이 적용된 빈이 주입 후보가 됩니다.

만약 여러 빈이 주입 후보로 선택되면, primary 속성이 true로 설정된 빈이 우선적으로 선택됩니다.
 


 

@Resource 어노테이션을 사용한 의존성 주입

 
Spring Framework에서 @Resource 어노테이션을 사용하여 의존성을 주입하는 방법에 대해 살펴보겠습니다. @Resource는 JSR-250 표준 어노테이션으로, 주로 Jakarta EE 환경에서 사용되지만, Spring에서도 지원됩니다.
 

1. @Resource 어노테이션 개요

@Resource 어노테이션은 필드나 세터 메서드에 적용되어 의존성을 주입하는 데 사용됩니다. 이 어노테이션은 주입할 빈을 이름으로 찾는 방식(즉, by-name)을 기본으로 합니다. 하지만 이름이 지정되지 않으면, 필드명이나 세터 메서드의 프로퍼티명을 기반으로 빈을 주입합니다.
 

2. @Resource 어노테이션 사용 예시

2.1. 이름을 지정한 @Resource 사용

다음은 @Resource 어노테이션을 사용하여 특정 이름의 빈을 주입하는 예제입니다.

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder") 
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
  • @Resource(name="myMovieFinder") 어노테이션을 사용하여, 이름이 myMovieFinder인 빈을 setMovieFinder 메서드에 주입합니다.
  • 이 방식은 빈의 이름을 명확히 지정하여 주입할 때 유용합니다.
     

2.2. 이름을 지정하지 않은 @Resource 사용

그럼 이제, 이름을 지정하지 않고 @Resource를 사용하는 방법을 살펴보겠습니다.

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
  • 이름을 지정하지 않으면, @Resource는 기본적으로 필드명(movieFinder)을 빈 이름으로 사용하여 주입합니다.
  • 즉, movieFinder라는 이름의 빈이 자동으로 주입됩니다.
     

3. @Resource를 사용한 필드 주입

@Resource 어노테이션은 필드에도 직접 사용할 수 있습니다. 다음은 필드에 @Resource를 사용하여 빈을 주입하는 예제입니다.

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context; 

    public MovieRecommender() {
    }
}
  • customerPreferenceDao 필드는 customerPreferenceDao라는 이름의 빈을 찾거나, 타입이 CustomerPreferenceDao인 빈을 주입받습니다.
  • context 필드는 ApplicationContext 타입의 빈을 주입받으며, 이는 Spring에서 자동으로 해결 가능한 의존성 중 하나입니다.
     

4. @Resource 어노테이션의 동작 방식

@Resource 어노테이션은 다음과 같은 순서로 주입할 빈을 찾습니다:

  1. 이름 매칭: @Resource에 지정된 이름으로 빈을 찾습니다. 이름이 지정되지 않았다면 필드명이나 메서드명에서 이름을 추출하여 사용합니다.
  2. 타입 매칭: 이름으로 찾지 못하면, 해당 필드나 메서드의 타입과 일치하는 빈을 주입합니다. 예를 들어, ApplicationContext와 같은 Spring에서 자동으로 해결 가능한 타입은 특별한 설정 없이도 주입됩니다.
     

5. 최근 @Resource 어노테이션 사용 감소와 그 이유


최근에는 @Resource 어노테이션이 점점 덜 사용되고 있습니다. 그 이유는 다음과 같습니다:

  • 타입 기반 주입의 선호: Spring에서는 이름 기반 주입보다는 타입 기반 주입이 더 선호됩니다. @Autowired 어노테이션은 타입에 따라 빈을 자동으로 주입하므로, 코드를 더 간결하게 유지할 수 있습니다. 또한, @Qualifier를 함께 사용하면 다중 빈 상황에서도 정확한 빈을 선택할 수 있어 더 유연한 구성이 가능합니다.
  • Spring Boot의 사용 증가: Spring Boot 프로젝트에서는 @Resource보다 @Autowired@Qualifier, 그리고 프로퍼티 주입을 위한 @Value 어노테이션이 더 일반적으로 사용됩니다. 이는 코드의 일관성을 유지하고, Spring Boot의 자동 설정 기능과 더 잘 맞기 때문입니다.
  • 표준 자바 어노테이션의 축소: @Resource는 JDK 11 이후로 더 이상 기본 자바 라이브러리의 일부가 아니며, Jakarta EE로 이전되었습니다. 이는 표준 자바 어노테이션에 의존하는 대신 Spring 고유의 어노테이션을 사용하는 트렌드를 가속화했습니다.
     

 

@Value 어노테이션을 사용한 프로퍼티 주입

 
Spring Framework에서 @Value 어노테이션을 사용하여 외부화된 프로퍼티를 주입하는 방법에 대해 설명드리겠습니다. @Value 어노테이션은 주로 환경 설정 파일이나 시스템 속성 등에서 값을 가져와 주입할 때 사용됩니다.
 

1. @Value 어노테이션 개요

@Value 어노테이션은 Spring에서 외부화된 프로퍼티를 주입하는 데 사용됩니다. 이 어노테이션은 문자열, 숫자, 배열 등 다양한 타입으로 변환하여 값을 주입할 수 있으며, Spring Expression Language (SpEL)을 사용하여 동적으로 값을 계산할 수도 있습니다.
 

2. @Value 어노테이션 사용 예시

2.1. 기본 사용 예

가장 기본적인 사용 예로, application.properties 파일에서 값을 가져와 주입하는 방법을 살펴보겠습니다.

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}
  • @Value("${catalog.name}") 어노테이션을 사용하여 application.properties 파일에서 catalog.name 프로퍼티의 값을 가져와 catalog 필드에 주입합니다.
  • 예를 들어, application.properties 파일에 catalog.name=MovieCatalog가 설정되어 있다면, catalog 필드에는 "MovieCatalog"가 주입됩니다.
     

2.2. @PropertySource와 함께 사용

프로퍼티 파일을 명시적으로 지정하여 사용하는 경우, @PropertySource 어노테이션을 사용하여 파일을 지정할 수 있습니다.

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
  • @PropertySource("classpath:application.properties")application.properties 파일을 로드하여 해당 파일의 프로퍼티를 사용하도록 설정합니다.
  • 이를 통해 @Value 어노테이션이 해당 파일에서 값을 읽어올 수 있게 됩니다.
     

2.3. 기본값 설정

만약 지정된 프로퍼티가 존재하지 않을 경우 기본값을 설정할 수도 있습니다.

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
        this.catalog = catalog;
    }
}
  • @Value("${catalog.name:defaultCatalog}")catalog.name 프로퍼티가 존재하지 않을 경우 "defaultCatalog"를 기본값으로 주입합니다.
     

3. 커스텀 타입 변환기 사용

Spring의 @Value 어노테이션은 기본적으로 문자열 값을 다른 타입으로 변환할 수 있지만, 커스텀 타입 변환기를 정의하여 사용할 수도 있습니다.

@Configuration
public class AppConfig {

    @Bean
    public ConversionService conversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        conversionService.addConverter(new MyCustomConverter());
        return conversionService;
    }
}
  • conversionService 빈을 정의하여, 커스텀 타입 변환기를 추가할 수 있습니다.
  • 이를 통해 @Value 어노테이션이 지정된 문자열 값을 원하는 커스텀 타입으로 변환할 수 있습니다.
     

4. SpEL을 사용한 동적 값 계산

@Value 어노테이션은 Spring Expression Language(SpEL)를 사용하여 동적으로 값을 계산할 수 있습니다.

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog'}") String catalog) {
        this.catalog = catalog;
    }
}
  • @Value("#{systemProperties['user.catalog'] + 'Catalog'}")는 시스템 속성 user.catalog"Catalog"를 추가한 값을 주입합니다.
  • SpEL을 사용하면 이처럼 복잡한 계산이나 조건에 따라 주입할 값을 동적으로 결정할 수 있습니다.
     

4.1. 복잡한 데이터 구조 주입

SpEL을 사용하여 복잡한 데이터 구조를 주입할 수도 있습니다.

@Component
public class MovieRecommender {

    private final Map<String, Integer> countOfMoviesPerCatalog;

    public MovieRecommender(@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
        this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
    }
}
  • @Value 어노테이션을 사용하여 Map<String, Integer> 타입의 데이터를 주입할 수 있습니다.
  • SpEL을 사용하여 복잡한 데이터 구조를 정의하고 이를 주입할 수 있습니다.
     

 

@PostConstruct@PreDestroy 을 사용한 빈의 라이프사이클 관리

 
Spring Framework에서 빈의 초기화와 소멸 시점을 관리하는 데 사용되는 @PostConstruct@PreDestroy 어노테이션에 대해 설명드리겠습니다. 이 어노테이션들은 JSR-250 표준에 속하며, Spring 2.5부터 지원됩니다.
 

1. @PostConstruct@PreDestroy 어노테이션 개요

@PostConstruct@PreDestroy 어노테이션은 각각 빈의 초기화 시점과 소멸 시점에 호출되는 메서드를 지정하는 데 사용됩니다. 이 어노테이션들은 CommonAnnotationBeanPostProcessor에 의해 인식되며, Spring의 ApplicationContext에 등록된 빈이 특정 라이프사이클 이벤트에서 호출되도록 합니다.

  • @PostConstruct: 빈이 초기화된 후(즉, 의존성 주입이 완료된 후) 호출됩니다.
  • @PreDestroy: 빈이 소멸되기 전에 호출됩니다.
     

2. @PostConstruct@PreDestroy 어노테이션 사용 예시

2.1. @PostConstruct 사용 예

다음은 @PostConstruct 어노테이션을 사용하여 빈의 초기화 시점에 캐시를 미리 채우는 예제입니다.

@Component
public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // 초기화 시점에 영화 캐시를 채웁니다...
    }
}
  • @PostConstruct 어노테이션이 붙은 populateMovieCache 메서드는 빈이 생성되고 의존성 주입이 완료된 후 자동으로 호출됩니다.
  • 이 메서드에서 필요한 초기화 작업을 수행할 수 있습니다.
     

2.2. @PreDestroy 사용 예

다음은 @PreDestroy 어노테이션을 사용하여 빈이 소멸되기 전에 캐시를 비우는 예제입니다.

@Component
public class CachingMovieLister {

    @PreDestroy
    public void clearMovieCache() {
        // 소멸되기 전에 영화 캐시를 비웁니다...
    }
}
  • @PreDestroy 어노테이션이 붙은 clearMovieCache 메서드는 빈이 소멸되기 전에 호출됩니다.
  • 이 메서드에서 리소스를 정리하거나 필요한 종료 작업을 수행할 수 있습니다.
     

3. Spring에서의 라이프사이클 관리

이 어노테이션들을 사용하기 위해서는 CommonAnnotationBeanPostProcessor가 Spring의 ApplicationContext에 등록되어 있어야 합니다. 일반적으로 Spring Boot 애플리케이션에서는 자동으로 이 설정이 활성화되므로 별도의 설정이 필요하지 않습니다.

3.1. JDK 9 이후의 변화

@PostConstruct@PreDestroy 어노테이션은 원래 JDK 6에서 JDK 8까지 표준 Java 라이브러리의 일부였습니다. 그러나 JDK 9 이후 javax.annotation 패키지가 Java의 기본 모듈에서 제거되었고, JDK 11부터는 완전히 삭제되었습니다. 따라서 이제는 jakarta.annotation-api 아티팩트를 Maven Central에서 다운로드하여 클래스패스에 추가해야 합니다.
 


 

어노테이션 기반의 컨피규레이션 메타데이터

 

1. 어노테이션 기반 설정 개요

Spring Framework에서는 XML 파일을 사용하지 않고도 어노테이션을 사용하여 설정을 정의할 수 있습니다. 이때, 자바 클래스를 이용하여 Spring 컨테이너를 설정하게 되며, 주로 @Configuration@Bean 어노테이션을 사용하여 빈을 정의하고 관리합니다.
 

1.1. @Configuration 어노테이션

@Configuration 어노테이션은 하나 이상의 @Bean 어노테이션이 선언된 메서드를 포함하는 클래스를 나타냅니다. 이 클래스는 애플리케이션 컨텍스트에서 빈 팩토리로 작동합니다.

@Configuration
public class AppConfig {

    @Bean
    public MovieCatalog movieCatalog() {
        return new MovieCatalog();
    }

    @Bean
    public MovieRecommender movieRecommender() {
        return new MovieRecommender(movieCatalog());
    }
}
  • AppConfig 클래스는 @Configuration 어노테이션을 사용하여 Spring 설정 클래스로 선언되었습니다.
  • movieCatalog()movieRecommender() 메서드는 각각 @Bean 어노테이션으로 빈을 정의합니다.
  • Spring 컨테이너는 이 메서드를 호출하여 빈을 생성하고 관리합니다.
     

1.2. @Bean 어노테이션

@Bean 어노테이션은 메서드 레벨에서 선언되며, 해당 메서드가 반환하는 객체를 Spring 컨테이너에서 관리하는 빈으로 등록합니다. 이를 통해 의존성 주입이 필요한 객체를 직접 구성할 수 있습니다.

@Bean
public MovieCatalog movieCatalog() {
    return new MovieCatalog();
}
  • movieCatalog() 메서드는 MovieCatalog 타입의 빈을 생성하며, Spring 컨테이너는 이 빈을 관리하고 다른 빈에서 필요할 때 주입합니다.
     

2. 컴포넌트 스캔과 @ComponentScan

Spring에서는 수동으로 모든 빈을 정의하지 않고도 자동으로 빈을 스캔하여 등록할 수 있습니다. @ComponentScan 어노테이션을 사용하면 특정 패키지를 스캔하여, 그 안에 정의된 @Component, @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스를 자동으로 빈으로 등록할 수 있습니다.
 

2.1. @ComponentScan 사용 예시

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
  • AppConfig 클래스는 @ComponentScan 어노테이션을 사용하여 com.example 패키지를 스캔합니다.
  • 이 패키지 안에서 @Component 등의 어노테이션이 붙은 모든 클래스가 자동으로 Spring 빈으로 등록됩니다.
     

2.2. @Component 어노테이션

@Component는 빈으로 등록될 수 있는 클래스를 나타내는 일반적인 어노테이션입니다. 이 외에도 특별한 용도의 어노테이션(@Service, @Repository, @Controller)이 있으며, Spring에서는 각각의 역할에 맞게 빈을 생성하고 관리합니다.

@Component
public class MovieCatalog {
    // ...
}
  • MovieCatalog 클래스에 @Component 어노테이션을 추가하면, @ComponentScan을 통해 자동으로 빈으로 등록됩니다.
     

3. 프로파일 관리와 @Profile 어노테이션

Spring에서는 환경별로 다른 설정을 적용할 수 있도록 @Profile 어노테이션을 제공합니다. 이 어노테이션을 사용하면 특정 프로파일에서만 활성화되는 빈을 정의할 수 있습니다.

@Configuration
public class DataSourceConfig {

    @Bean
    @Profile("development")
    public DataSource devDataSource() {
        // 개발용 데이터 소스 설정
        return new DataSource("devDB");
    }

    @Bean
    @Profile("production")
    public DataSource prodDataSource() {
        // 운영용 데이터 소스 설정
        return new DataSource("prodDB");
    }
}
  • @Profile("development") 어노테이션을 사용하여 개발 환경에서만 활성화되는 devDataSource 빈을 정의할 수 있습니다.
  • 마찬가지로 @Profile("production")을 통해 운영 환경에서 사용할 prodDataSource 빈을 정의합니다.
     

4. @Import를 사용한 설정 클래스 분리

설정 클래스가 많아지면 코드가 복잡해질 수 있습니다. 이때 @Import 어노테이션을 사용하여 설정 클래스를 분리하고, 하나의 설정 클래스에서 다른 설정 클래스를 불러올 수 있습니다.

@Configuration
@Import({DataSourceConfig.class, AnotherConfig.class})
public class AppConfig {
}
  • AppConfig 클래스에서 @Import 어노테이션을 사용하여 DataSourceConfigAnotherConfig 클래스를 불러옵니다.
  • 이를 통해 설정 클래스를 모듈화하여 관리할 수 있습니다.
     

 

참고자료 : Spring 공식 문서의 Annotation-based Container Configuration