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

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

🌱 Spring Bean Management: depends-on, Lazy-initialized Beans, Autowiring

Spring에서는 빈(Bean)의 초기화 순서, 지연 로딩(Lazy Initialization), 자동 주입(Autowiring) 을 통해 효율적인 객체 생성 및 관리 를 수행할 수 있습니다.
이번 정리에서는 이러한 개념들을 명확히 설명하고, 활용 방법을 소개하겠습니다.

1️⃣ Using @DependsOn: 빈 초기화 순서 제어

🔹 @DependsOn이란?

  • 특정 빈이 생성되기 전에 먼저 초기화해야 할 빈을 지정하는 어노테이션
  • 빈 간의 의존성을 명시적으로 정의하여, 초기화 순서를 강제할 수 있음
  • 다수의 빈을 순차적으로 초기화 가능

예제: @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") // 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"}) // manager, accountDao 빈이 먼저 초기화된 후 실행
    public ExampleBean beanOneWithMultipleDependencies() {
        ExampleBean exampleBean = new ExampleBean();
        exampleBean.setManager(manager());
        return exampleBean;
    }
}

📌 특징
빈 간의 초기화 순서를 제어할 수 있음
데이터베이스 연결, 외부 리소스 로드 등 특정 빈을 먼저 실행해야 할 경우 유용

2️⃣ Using @Lazy: 빈의 지연 초기화 (Lazy Initialization)

🔹 Lazy Initialization이란?

  • 빈이 필요할 때까지 초기화를 지연시키는 방식
  • 애플리케이션 실행 속도를 높이고, 불필요한 리소스 사용을 방지

개별 빈에 대해 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 // lazyBean은 처음 사용될 때까지 초기화되지 않음
    public ExpensiveToCreateBean lazyBean() {
        return new ExpensiveToCreateBean();
    }

    @Bean
    public AnotherBean notLazyBean() {
        return new AnotherBean(); // 즉시 초기화됨
    }
}

모든 빈을 Lazy Initialization으로 설정

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

@Configuration
@Lazy // 이 클래스 내의 모든 빈을 lazy-initialized로 설정
public class AppConfig {

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

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

📌 특징
리소스를 많이 사용하는 빈(예: DB 연결, 대형 객체 등)의 초기화를 지연시켜 성능 최적화
모든 빈을 @Lazy로 설정하면, 최초 요청이 있을 때만 빈을 생성함

3️⃣ Autowiring: 자동 의존성 주입

🔹 Autowiring이란?

  • Spring이 자동으로 의존성을 찾아서 주입하는 기능
  • @Autowired, @Qualifier, @Primary 등을 활용하여 특정 빈을 자동 주입할 수 있음
  • Spring 컨테이너가 적절한 빈을 찾아 연결하므로, 수동 설정 없이 객체를 주입할 수 있음

Autowiring 방식 4가지

Autowiring 모드 설명
no (기본값) 자동 주입을 사용하지 않음. 의존성은 명시적으로 정의해야 함.
byName 속성 이름과 동일한 이름을 가진 빈을 찾아 주입
byType 속성 타입과 일치하는 빈을 찾아 주입
constructor 생성자의 아규먼트 타입과 일치하는 빈을 주입

1. @Autowired 를 사용한 자동 주입

Spring은 타입을 기준으로 적절한 빈을 찾아 주입합니다.

예제: 생성자 기반 @Autowired

@Component
public class Service {
    private final Repository repository;

    // 생성자 주입 (권장 방식)
    @Autowired
    public Service(Repository repository) {
        this.repository = repository;
    }

    public void performAction() {
        repository.save();
    }
}

예제: 세터 기반 @Autowired

@Component
public class Service {
    private Repository repository;

    @Autowired
    public void setRepository(Repository repository) {
        this.repository = repository;
    }
}

2. @Qualifier 를 사용하여 특정 빈 지정

Spring이 같은 타입의 여러 빈을 찾을 경우, 명확히 특정 빈을 지정해야 할 때 사용

@Component("mainRepository")
public class MainRepository implements Repository {
    public void save() {
        System.out.println("Main Repository: Data saved!");
    }
}

@Component("backupRepository")
public class BackupRepository implements Repository {
    public void save() {
        System.out.println("Backup Repository: Data saved!");
    }
}

@Component
public class Service {
    private final Repository repository;

    @Autowired
    public Service(@Qualifier("mainRepository") Repository repository) {
        this.repository = repository;
    }
}

📌 특징
같은 타입의 여러 빈이 존재할 때, 특정 빈을 지정하여 주입 가능
@Qualifier를 사용하지 않으면, 모호성(ambiguity) 오류 발생 가능

3. @Primary 를 사용하여 기본 빈 지정

  • 여러 개의 동일한 타입 빈이 존재할 경우, 디폴트로 선택할 빈을 지정
  • 명시적으로 @Qualifier를 사용하지 않더라도, @Primary가 있는 빈이 기본적으로 주입됨
@Component
@Primary
public class DefaultRepository implements Repository {
    public void save() {
        System.out.println("Default Repository: Data saved!");
    }
}

@Component
public class AlternativeRepository implements Repository {
    public void save() {
        System.out.println("Alternative Repository: Data saved!");
    }
}

📌 특징
우선적으로 주입될 빈을 지정 가능
@Qualifier 없이도 디폴트 빈을 자동 선택 가능

4️⃣ 순환 의존성 (Circular Dependency) 문제 해결

🔹 순환 의존성이란?

  • A가 B를 필요로 하고, B가 다시 A를 필요로 하는 무한 루프 구조
  • Spring이 빈을 생성하는 과정에서 BeanCurrentlyInCreationException 발생

해결 방법 1: 세터 주입 사용

@Component
public class A {
    private B b;

    @Autowired
    public void setB(B b) {
        this.b = b;
    }
}

해결 방법 2: @Lazy 사용

@Component
public class A {
    private final B b;

    @Autowired
    public A(@Lazy B b) {
        this.b = b;
    }
}

📌 순환 의존성 해결 방법
세터 주입 사용
@Lazy를 활용하여 객체 생성 시점을 지연

🎯 Summary (요약)

🔹 @DependsOn빈 초기화 순서 강제 설정 가능
🔹 @Lazy리소스를 많이 사용하는 빈을 지연 로딩하여 성능 최적화
🔹 @Autowired + @Qualifier + @Primary빈 자동 주입 및 충돌 해결 가능
🔹 순환 의존성 해결세터 주입 또는 @Lazy 활용

 

🚀 이러한 기술을 적절히 활용하면 유지보수성이 높은 확장 가능한 애플리케이션을 개발할 수 있습니다! 🎯

'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