Spring IoC 컨테이너

이상민·2021년 8월 20일
0

스프링

목록 보기
3/9
post-thumbnail

1. Inversion of Control

  • 일반적인 제어의 흐름은 각 객체에게 제어권이 있는 것으로 객체 자신이 사용할 객체를 스스로 선택하고 스스로 생성한다

  • 프레임워크에서 제어는 프레임워크에게 있다. 단순히 불러와 사용하는 라이브러리와 달리 개발자가 작성한 어플리케이션 코드가 프레임워크에 의해 사용되기 때문. 이런 일반적인 제어의 흐름과 반대되는 것이 IoC이다


2. IoC 컨테이너

객체의 생성파괴, 조합, 객체간 의존 관계를 설정하는 객체

  • 어떠한 클래스를 사용할지 등록하면, 필요한 의존 관계를 맺고 생명 주기를 관리해 인스턴스를 반환한다

  • IoC 컨테이너 객체를 클라이언트로 객체들은 의존성을 주입 받을 수 있어 결합도가 느슨해진다

  • 스프링에선 ApplicationContext 인터페이스를 통해 이를 제공한다


3. ApplicationContext

스프링의 IoC 컨테이너

  • ApplicationContext에 의해 관리되는 객체들을 Bean이라고 한다

  • ApplicationContext은 실제 만들어야할 Bean 정보를 Configuration Metadata로부터 받아온다. 이는 자바(AnnotationConfigApplicationContext) 또는 xml(GenericXmlApplicationContext)로 작성할 수 있다

3-1. ApplicationContext의 기본 사용

// AppConfiguration.java

@Configuration  // 스프링의 애노테이션으로 ApplicationContext의 설정 메타데이터로 인식되게 한다 
public class AppConfiguration {

    @Bean  // 아래 메소드는 Bean을 정의한 Configuration Metadata가 된다 
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }
    
}
// 설정파일로 어플리케이션 컨택스트 생성 
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfiguration.class);
// Bean 생성 
ExampleBean exBean = applicationContext.getBean(ExampleBean.class);
  • ClassName.class :

3-2. Bean을 인자로 연결하기

  • 아래처럼 Configuration 내 메소드를 호출하는 방식으로 Bean 간 의존성을 설정할 수도 있지만
@Configuration 
public class AppConfiguration {

    @Bean  
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }
    
    @Bean
    public AnotherBean antoherBean() {
        return new AnotherBean(exampleBean());
    }
    
}
  • 조금 더 보기 좋게 인자로 주입할 수도 있다. 스프링이 알아서 처리해준다
@Configuration 
public class AppConfiguration {

    @Bean  
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }
    
    @Bean
    public AnotherBean antoherBean(ExampleBean exampleBean) {
        return new AnotherBean(exampleBean);
    }
    
}
  • 스프링은 생성자 기반 DI를 추천한다. 어느 시점에도 null 멤버가 없음을 보장할 수 있는 한편 final 키워드를 통해 멤버 변수를 불변으로 만들 수도 있기 때문

3-3. Bean 순환 의존 문제

  • 다른 순환 의존 문제와 마찬가지로, Bean끼리 순환적으로 의존시 교착상태가 발생해 오류가 발생한다
// ObjectA는 ObjectB의 인스턴스의 생성을 기다리고 ObjectB는 ObjectA의 인스턴스 생성을 기다린다

@Configuration 
public class AppConfiguration {

    @Bean
    public ObjectA objectA(ObjectB objectB) {
        return new ObjectA(objectB);
    }
    
    @Bean
    public ObjectB objectB(ObjectA objectA) {
        return new ObjectB(objectA);
    }

}

4. Bean의 생명주기 콜백

위에서 설정 파일을 통해 ApplicationContext를 생성하고, close()로 소멸할 수 있다

applicationContext.close();
  • application context가 소멸되면, 등록되어 있는 Bean들도 소멸된다

  • close()로 Application Context를 소멸하지 않으면 Bean 소멸 콜백도 호출되지 않는다

  • 콜백 함수 : 다른 코드의 인수로서 넘겨주는 실행 가능한 코드. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 나중에 실행할 수도 있다

4-1. 생성 콜백 : 생성 후 작업하기

  1. @PostConstruct 애너테이션이 적용된 메소드 호출 (있다면)
  2. Bean이 InitializingBean 인터페이스 구현시 afterPropertiesSet 호출
  3. @Bean 애너테이션의 initMethod에 설정한 메소드 호출
@Component
public class SomeComponent implements InitializingBean {
    // @PostConstruct 적용 메소드
    @PostConstruct
    public void postConstruct() {
        System.out.println("postConstruct 호출");
    }

    // InitializingBean 구현 메소드
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet 호출");
    }
}


...다른파일...


@Configuration
public class Config {
    // initMethod 설정 메소드
    @Bean(initMethod = "init")
    public Component component() {
        ...
    }
}

class Component {
    public void init() {
        ...
    }
}

4-2. 소멸 콜백 : 소멸 후 작업하기

  1. @PreDestroy 애너테이션이 적용된 메소드 호출 (있다면)
  2. Bean이 DisposableBean 인터페이스 구현시 destroy 호출
  3. @Bean 애너테이션의 destroyMethod에 설정한 메소드 호출
@Component
public class SomeComponent implements DisposableBean {
    @PreDestroy
    public void preDestroy() {
        System.out.println("preDestroy 호출");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy 호출");
    }
}

...다른파일...


@Configuration
public class Config {
    // destroyMethod 설정 메소드
    @Bean(destroyMethod = "destroyMethod")
    public Component component() {
        ...
    }
}

class Component {
    public void destroyMethod() {
        ...
    }
}
profile
편하게 읽기 좋은 단위의 포스트를 추구하는 개발자입니다

0개의 댓글