본문 바로가기
Java/Spring

[4] 스프링 프레임워크 핵심 - IOC 컨테이너와 Bean

by Riverandeye 2020. 11. 30.

스프링의 디자인 철학

- 모든 선택은 개발자의 몫이다 (특정 기술을 강요하지 않는다)

- 다양한 관점을 지향한다 (유연성)

- 하위 호환성을 지킨다 (노력)

- API를 신중하게 설계 한다

- 높은 수준의 코드를 지향한다

 

IoC 컨테이너

IoC 컨테이너를 사용하는 이유를 여럿 찾아봤는데

stackoverflow.com/questions/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code

이 글에서 대화를 나눈게 가장 적합한 대답이 아닐까 생각됩니다. 

 

스프링에서는 어노테이션 기반의 DI가 수행되는데요

google guice에서 처음 선보인 거라고 하네요 (역시 구글)

 

BeanFactory

IoC 컨테이너의 최상위 인터페이스

이 인터페이스가 가장 핵심적인 인터페이스이고 구현체도 다양합니다.

 

docs.spring.io/spring-framework/docs/5.0.8.RELEASE/javadoc-api/org/springframework/beans/factory/BeanFactory.html

BeanFactory의 Lifecycle에 대해 나와있습니다. 이건 개별 글로 정리를 해야겠습니다.

컨테이너 안의 빈을 가공하거나 하는 절차들에 대해 나와있습니다. 

 

Bean

IoC 컨테이너가 관리하는 객체

어노테이션이 없는 경우엔 Bean이라고 할 수 없습니다 (Java Bean일순 있다 getter setter가 있으니까 ㅋㅋ)

Repository, Service 등 과 같은 어노테이션이 있는 경우엔 Bean으로 등록이 된다. 

 

왜 IoC 컨테이너가 관리하느냐 하면

우선 의존성 주입을 대신 해주는게 정말 편리합니다. 

Bean의 Scope를 Singleton으로 관리하고 싶을 때도 Bean으로 만들면 편합니다.

IoC 컨테이너의 Bean들은 기본적으로 Singleton 으로 구성됩니다. 

 

또, Bean의 Lifecycle을 관리하는데도 큰 도움이 됩니다.

@PostConstruct와 같은 Lifecycle 객체를 이용하면,

Bean의 생애주기에 따라 특정 메소드를 정의하여 호출할 수 있습니다. 

 

ApplicationContext

 

docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html

ApplicationContext는 BeanFactory의 기능 뿐 만 아니라 다른 여러 기능들을 가지고 있습니다. 

EnvironmentCapable, HierarchicalBeanFactory, ListenableBeanFactory 

MessageSource는 메세지 다국화 (i18n) 를 위해 존재합니다

ResourceLoader는 리소스를 읽어오는 기능을 합니다

BeanFactory 외의 다양한 기능을 합니다 

 

우린 이 ApplicationContext를 이용하여 Bean을 관리하게 됩니다

 

xml을 이용한 Bean 관리

 

아주 고전적인 bean 설정을 이용해봅시다. 

resource > new > XMLConfiugrationfile > Spring Config

xml 설정

이름은 application.xml로 짓습니다.

 

이런식으로 주입하면, springApplication 없이 applicationContext 에서 classPathXmlApplicationContext를 호출하여 bean의 의존관계를 확인할 수 있습니다.

 

xml에서 component-scan 을 적용하면 @Component로 어노테이션 된 컴포넌트를 자동으로 스캔합니다.

<context:component-scan ~~/>

주입은 @Autowired나 @Inject를 명시해주면 자동으로 주입해줍니다. 

 

Java로 Configuration 등록하기

 

다음과 같이 @Configuration 어노테이션이 붙어있는 객체를 생성합니다. 

@Configuration
public class ApplicationConfig {

    @Bean
    public BookRepository bookRepository(){
        return new BookRepository();
    }

    @Bean
    public BookService bookService(){
        BookService bookService = new BookService();
        bookService.setBookRepository(bookRepository());
        return bookService;
    }
}

 

위에서는 의존성 주입을 설정에서 직접 해줬는데, @Autowired 로도 충분히 가능합니다. 

그 후 AnnotationConfigApplicationContext 를 이용하면 이를 사용할 수 있습니다.

public static void main(String[] args) {
	ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
}

 

ComponentScan이 적용된 ApplicationConfig를 이용하기

@Configuration
@ComponentScan(basePackageClasses = ApplicationcontextApplication.class)
public class ApplicationConfig {

}

더욱 간단해졌습니다. ComponentScan을 지정하면

해당 class의 동일 및 하위 디렉토리에 있는 모든 대상들에 대해서 Bean화를 진행합니다. 

 

@SpringBootApplication 을 이용하기

사실 @SpringBootApplication에 위 ComponentScan 설정이 들어가있어서 

해당 클래스의 하위 디렉토리의 모든 대상들이 Bean으로 등록됩니다. 

댓글