Using depends-on, Lazy-initialized Beans, Autowiring Collaborators

2024. 11. 14. 12:22Spring Framework/Spring IoC

Using depends-on

Spring의 Java 기반 구성에서는 @DependsOn 어노테이션을 사용하여 빈 간의 초기화 순서를 지정할 수 있습니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Configuration
public class AppConfig {

    @Bean
    @DependsOn("manager")
    public ExampleBean beanOne() {
        ExampleBean exampleBean = new ExampleBean();
        exampleBean.setManager(manager());
        return exampleBean;
    }

    @Bean
    public ManagerBean manager() {
        return new ManagerBean();
    }

    @Bean
    public JdbcAccountDao accountDao() {
        return new JdbcAccountDao();
    }

    @Bean
    @DependsOn({"manager", "accountDao"})
    public ExampleBean beanOneWithMultipleDependencies() {
        ExampleBean exampleBean = new ExampleBean();
        exampleBean.setManager(manager());
        return exampleBean;
    }
}

위 코드에서:

  • @DependsOn("manager")를 사용하여 beanOne이 manager 빈이 먼저 초기화된 후에 초기화되도록 지정합니다.
  • @DependsOn({"manager", "accountDao"})를 사용하여 beanOneWithMultipleDependencies가 manager와 accountDao 빈이 모두 초기화된 후에 초기화되도록 지정합니다.

Lazy-initialized Beans

@Lazy 어노테이션을 사용하여 lazy-initialized 빈을 정의할 수 있습니다. 또한, 컨테이너 레벨에서 모든 빈을 lazy-initialized로 설정하려면 @Configuration 클래스에 @Lazy 어노테이션을 추가할 수 있습니다.

개별 빈에 대한 lazy initialization

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class AppConfig {

    @Bean
    @Lazy
    public ExpensiveToCreateBean lazyBean() {
        return new ExpensiveToCreateBean();
    }

    @Bean
    public AnotherBean notLazyBean() {
        return new AnotherBean();
    }
}

위 코드에서:

  • @Lazy 어노테이션을 lazyBean 메서드에 추가하여 해당 빈이 처음 요청될 때까지 초기화되지 않도록 설정합니다.
  • notLazyBean은 별도의 어노테이션이 없기 때문에, 기본적으로 즉시 초기화됩니다.

컨테이너 레벨의 lazy initialization
모든 빈을 lazy-initialized로 설정하려면, @Configuration 클래스에 @Lazy 어노테이션을 추가할 수 있습니다:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
@Lazy
public class AppConfig {

    @Bean
    public ExpensiveToCreateBean lazyBean() {
        return new ExpensiveToCreateBean();
    }

    @Bean
    public AnotherBean notLazyBean() {
        return new AnotherBean();
    }
}

위 코드에서는 @Lazy 어노테이션이 @Configuration 클래스 레벨에 적용되어, 이 클래스 내의 모든 빈이 lazy-initialized 됩니다.

Autowiring Collaborators

Spring에서는 autowiring(자동 주입)을 통해 컨테이너가 빈 간의 의존성을 자동으로 해결하고 주입할 수 있습니다. 이는 구성 컴포넌트간의 관계를 관리하기 위해 ApplicationContext의 내용을 검사하여 적합한 빈을 찾고 주입하는 방식입니다. Autowiring은 의존성 관리를 단순화하는 강력한 도구로, 특히 개발 초기 단계에서 유용합니다. 그러나 장점, 모드, 제한 사항, 그리고 세밀한 제어 기술이 따릅니다.

Autowiring의 장점

  1. 구성 설정의 간소화
    Autowiring은 의존성을 수동으로 지정하지 않아도 되므로 속성(property)이나 컨스트럭터 아규먼트(argument)를 명시적으로 설정할 필요가 줄어듭니다. 적합한 빈이 컨테이너에 존재하면 자동으로 해결됩니다.
  2. 변화에 대한 적응력
    객체가 변화함에 따라 autowiring은 새로운 의존성을 기존 설정을 수정하지 않고도 해결할 수 있습니다. 예를 들어, 클래스에 새로운 의존성이 추가되면 Spring이 자동으로 이를 주입합니다.
  3. 개발 초기 단계에서의 유연성
    Autowiring은 설계가 발전하는 초기 개발 단계에서 특히 유용합니다. 명시적 설정이 필요 없으므로 빠르게 프로토타입을 작성할 수 있습니다. 이후, 더 명확하고 안정적인 구성을 위해 명시적 설정으로 전환할 수 있습니다.

Autowiring 모드

Spring은 4가지 autowiring 모드를 제공하며, 각 모드는 XML 구성에서 <bean>autowire 속성을 사용하거나 Java 구성에서 어노테이션으로 설정할 수 있습니다.

1. no (기본 모드)

  • 동작: Autowiring이 비활성화됩니다. 모든 의존성은 <ref/> 등을 사용하여 명시적으로 정의해야 합니다.
  • 장점:
    • 명시적 설정은 더 큰 명확성과 제어를 제공합니다.
    • 빈 간의 관계를 구성 파일에 명확히 문서화할 수 있습니다.
  • 사용 사례: 명시적 설정이 선호되는 안정적인 대규모 애플리케이션에 적합합니다.

2. byName

  • 동작: 속성 이름과 동일한 이름을 가진 빈을 찾아 주입합니다.
    예: setMaster() 메서드가 있는 경우, 이름이 master인 빈을 찾아 주입합니다.
  • 장점:
    • 빈 이름을 통해 정확히 일치하는 빈을 선택할 수 있습니다.
  • 제한 사항:
    • 일치하는 이름의 빈이 없으면 속성이 설정되지 않습니다.
    • 일관된 이름 규칙이 필요합니다.
  • 사용 사례: 빈 이름 규칙이 엄격히 관리되는 경우.

3. byType

  • 동작: 속성의 타입과 동일한 타입의 빈을 찾아 주입합니다.
  • 장점:
    • 빈 이름에 의존하지 않고 타입을 기준으로 주입을 처리합니다.
    • 배열, 컬렉션, Map 타입도 지원합니다.
  • 제한 사항:
    • 요구되는 타입의 빈이 둘 이상 있으면 치명적 예외가 발생합니다.
    • 일치하는 빈이 없으면 속성이 설정되지 않습니다.
  • 사용 사례: 타입이 고유한 경우에 적합합니다.

4. constructor

  • 동작: byType과 유사하지만 생성자 인자에 적용됩니다. Spring은 생성자 인자의 타입에 따라 빈을 주입합니다.
  • 장점:
    • 생성자를 통해 복잡한 의존성을 처리할 수 있습니다.
    • 배열, 컬렉션, Map 타입도 지원합니다.
  • 제한 사항:
    • 요구되는 타입의 빈이 둘 이상 있거나 일치하는 빈이 없으면 치명적 예외가 발생합니다.
  • 사용 사례: 생성자 주입을 선호하는 경우에 적합합니다.

특별한 케이스 (byType 및 constructor)

  • 컬렉션 및 Map:
    • 배열과 특정 타입의 컬렉션은 컨테이너에 존재하는 모든 적합한 빈을 포함합니다.
    • Map의 키가 String일 경우, 키는 빈 이름이 되고 값은 해당 빈 인스턴스가 됩니다.

Autowiring의 한계와 단점

  1. 모호성(Ambiguity):
    여러 빈이 동일한 타입과 일치하면 Spring은 어떤 빈을 주입해야 할지 판단할 수 없습니다. 추가적인 자격 지정(qualifier)이 필요합니다.
  2. 명확성 감소:
    Autowiring은 빈 간의 관계를 숨기므로 시스템 구조를 문서화하거나 이해하기 어렵게 만듭니다.
  3. 재정의(Override):
    속성(property)이나 생성자 인자(argument)에 명시적으로 정의된 의존성이 Autowiring보다 우선합니다.
  4. 제외(Exclusion):
    기본 타입(primitive), String, Class, 또는 이들의 배열은 autowiring을 지원하지 않습니다.
  5. 도구 및 문서화 문제:
    Spring 컨테이너에서 관계를 문서화하는 도구가 Autowiring으로 생성된 관계를 정확히 반영하지 못할 수 있습니다.

모호성 해결 및 Autowiring 제외

모호성 해결 옵션

  1. Autowiring 비활성화:
    문제가 되는 빈에 대해 명시적 설정을 사용합니다.
  2. Autowiring 제외:
    특정 빈을 Autowiring 대상에서 제외하려면 XML에서는 autowire-candidate 속성을 false로 설정하고, Java 구성에서는 autowireCandidate = false로 설정합니다.
    • XML 예제:
      <bean id="myBean" class="com.example.MyClass" autowire-candidate="false"/>
    • Java 예제:
      @Bean(autowireCandidate = false)
      public MyClass myBean() {
          return new MyClass();
      }
  3. Primary 빈 지정:
    우선적으로 주입할 빈을 설정하려면 primary = true로 설정합니다.
    • XML 예제:
      <bean id="primaryBean" class="com.example.MyClass" primary="true"/>
    • Java 예제:
      @Bean
      @Primary
      public MyClass primaryBean() {
          return new MyClass();
      }
  4. Qualifier 사용:
    @Qualifier 어노테이션을 사용하여 특정 빈을 지정합니다.

 

Java 구성의 기본 및 세밀한 제어

Default Candidate와 Autowire Candidate

  1. defaultCandidate:
    defaultCandidate = false로 설정된 빈은 추가적인 자격 지정(qualifier)이 없으면 Autowiring에서 제외됩니다.
  2. autowireCandidate:
    autowireCandidate = false로 설정된 빈은 타입 기반 Autowiring에서 완전히 제외됩니다.

패턴 기반 Autowire 후보 선택

XML 구성에서 Autowire 후보를 패턴으로 제한할 수 있습니다.

  • XML 예제:
  • <beans default-autowire-candidates="*Repository"> <bean id="myRepository" class="com.example.MyRepository"/> <bean id="notAutowireable" class="com.example.NotAutowireable"/> </beans>
  • *Repository로 끝나는 이름의 빈만 Autowire 대상으로 간주됩니다.

Annotation 기반 구성

@Autowired, @Primary, @Qualifier와 같은 어노테이션을 사용하여 Autowiring을 처리할 수 있습니다. 이는 현대 Spring 애플리케이션에서 일반적입니다.

  • 예제: 
  •  
  • @Service public class MyService { @Autowired @Qualifier("specificBean") private MyDependency dependency; }

Autowiring은 의존성 관리를 단순화하고 자동화하지만, 모호성과 명확성 부족과 같은 문제를 초래할 수 있습니다. 개발 초기에는 유용하지만, 더 큰 프로젝트에서는 명시적 설정이 선호될 수 있습니다. Exclusion, Primary 빈 지정, Qualifier 사용과 같은 기술을 통해 더 정교하게 제어할 수 있습니다.

'Spring Framework > Spring IoC' 카테고리의 다른 글

Bean Scopes  (0) 2024.11.14
Method Injection  (0) 2024.11.14
Dependencies  (0) 2024.11.14
Dependency Injection  (0) 2024.06.11
Bean Overview  (0) 2024.06.11