Notice
Recent Posts
Recent Comments
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
07-01 00:27
Archives
Today
Total
관리 메뉴

Developer_Neo

[Spring] - 스프링 컨테이너 본문

Spring

[Spring] - 스프링 컨테이너

_Neo_ 2022. 8. 17. 15:04
반응형

스프링 컨테이너(Spring Container)(Spring IOC Container)

Bean들의 생명주기(Life Cycle)를 관리한다 즉, Bean 생성, 관리, 제거 등의 역할을 담당한다.
Spring Framework에서 IOC를 사용한다고 하였는데
IOC(제어의 역전)는 Spring Bean들의 생명주기를 관리하기 위해 사용한다.

스프링 컨테이너가 빈을 관리하는 과정은 DI(의존성 주입)가 이루어진 빈들을 BeanFactory와 ApplicationContext라는 2개의 컨테이너로 제어하고 관리한다.

BeanFactory와 ApplicationContext는 인터페이스로 각 구현체가 여러개가 있다.
이 구현체를 사용하는 경우는 우리가 MVC패턴에 맞추어 코드를 작성하고, Test를 하기 위함일 때 사용한다.

 


BeanFactory와 ApplicationContext를 알아보기 이전에 스프링 컨테이너를 사용하는 지 알아보자

우리가 자바를 배울 때 객체로써 사용하기 위해서는 new생성자가 꼭 필요했다. 그런데 이렇게 하게 되면, 객체 지향프로그래밍이라는 Java가 좋은 객체 지향 프로그래밍의 원칙을 지키지 못하게 됩니다. 왜냐하면, 객체가 많이 존재하게 됨에 따라 서로 어지럽게 참조가 되어 있을 것입니다. 이때 참조가 심하면, 서로에 대한 의존성이 높다는 것입니다. 그러면, 좋은 객체 설계 지향원칙에 따라 DIP에 위반이 됩기 때문입니다.
따라서 좋은 객체 지향 설계원칙을 따르려고 이리저리 개발을 하다가 나온것이 Spring인데 이때 객체 간의 의존성을 낮추기 위해 Spring 컨테이너가 사용됩니다. 
즉, 좋은 객체지향 설계를 하고, 객체 간의 의존성을 낮추기 위해 Spring 컨테이너를 사용합니다

 


 

위의 그림은 ApplicationContext 인터페이스가 다른 인터페이스들을 다중 상속하고 있는 모습을 보여주고 있다.

MessageSource : 다국어 메시지 처리 기능 제공
EnvironmentCapable : 프로파일 기능, 프로퍼티 기능들을 제공
BeanFactory :스프링 빈을 관리하고 조회하는 역할 담당
ApplicationEventPublisher : 이벤트 기반의 프로그래밍을 할 때 필요한 기능을 제공
ResourceLoader : 리소스를 읽어오는 기능을 제공

그러면, ApplicationContext는 다중 상속하고 있는 기능들을 다 가지고 있는 것이다.

한마디로 정리하면, BeanFactory기능을 모두 상속해 Bean 객체를 관리하며, 메시지 처리, 리소스, 이벤트와 관련된 기능을 추가적으로 가지고 있는 인터페이스이다.

 


 

그러면 Bean의 생명주기를 관리해주는 BeanFactory가 있는데 왜 똑같은 기능을 제공해주는 ApplicationContext가 또 있는가?라고 생각이 들 수 있다.

 

주로 BeanFactory보다는 ApplicationContext를 사용을 더 많이 하게 됩니다. 왜냐하면, 애플리케이션을 개발할 때는 빈 관리, 조회하는 기능외에 수많은 부가 기능이 필요하기 때문입니다.

한국어로 설정시
일본어로 설정

예로 보면,  위는 msn사이트이다. 여기에서는 톱니바귀의 설정표시를 누르면 언어의 변경이 가능하다.
이와 같이 다국어에 대한 처리를 MessagerSource라는 인터페이스를 이용해 할 수 있다.
Spring은 i18n설정을 지원하고 있기에 application.properties에 다국어 처리에 대한 설정을 해주면 HTTP Request에서의 Content-Language헤더 정보를 이용해 처리할 수 있을거라고 예상해본다.

위의 그림을 보면, 

BeanFactory : 스프링 컨테이너의 최상위 인터페이스이며, getBean메서드를 제공한다.

ApplicationContext를 구현한 구현체들은 FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigApplicationContext들이 있으며, 자주 사용할 것은 AnnotationConfigApplicationContext이다.

BeanFactory와 ApplicationContext의 빈 생성 시기 차이점

BeanFactory는 Bean을 미리 생성하지 않는다. 그러면 언제 생성되는가? getBean을 사용해서 호출된 시점에 빈을 생성한다.

ApplicationContext는 App을 실행할 떼 Context초기화시점이 있는데 이 시점에 모든 Singleton 빈을 미리 다 생성하고, Application이 시작된 이후에는 빈이 이미 다 생성되어있기 때문에 빈을 지연없이 제공하고 받는다.

 

싱글톤 객체가 사라지는 시점은 Applicaton이 종료되는 시점이다.


Java Bean VS Spring Bean

Bean : 애플리케이션에서 사용하는 객체 (일반적으로 Bean이라고 하면, Spring Bean을 나타냄)
Java Bean : 단순히 클래스에서 Getter./Setter만 가지고 있는 클래스(객체)
Spring Bean : Spring 컨테이너가 관리하는 자바 객체

 


우리가  직접적으로 Spring Container를 사용하기 위해서는 

1. ApplicationContext 의 구현체인 AnnotationConfigApplicationContext와 (에노테이션 기반의 자바 설정 클래스)(Configuration Metadata)@Configuration이 적용되어 있는 클래스 파일이용해서 객체를 만들어야 합니다. -> 이렇게 하면, Spring Container를 지정해서 사용할 수 있게 됩니다.

스프링 컨테이너는 Configuration Metadata인 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.

Configuration Metadata는 위에서 설명한 @Configuration 어노테이션과 추가적으로 @Bean 어노테이션으로 설정이 가능하다. 하지만 다른 2가지 방법도 존재한다. 
1. XML을 이용
2. 자바 코드를 이용
이다.

 

2. Spring Container 에 등록된 빈들을 가지고 와서 쓰려면 getBean메서드를 이용해서 가져와서 사용하면 된다. (getBean을 통해 빈을 가져오게 되면, 빈의 이름을 알아야하기에 주도권이 개발자에게 가게 되어 IOC가 깨진다. getBean을 어쩔수 없이 사용해야되는 경우를 빼고선 잘 사용하지 않는다)


Q. 그러면, Spring Container에서 빈의 생명주기를 관리한다고 하였고 위에서도 Spring Container안에 있는 빈을 가져온다고 한다. 그러면! 빈을 어떻게 생성해서 가지고 있을 까?

A. Spring Contatiner에서 Bean을 BeanDefinition라는 추상화로써 Spring Bean으로 가지고 있어서 가능하다.

설명을 덧붙이자면, 위에서 SpringContainer를 생성시 Configuration Metadata로써 어노테이션 기반의 클래스 파일을 넘겨 받는다고 하였다. 결국에는 이 클래스 파일파라미터로 전달되면, 내부적으로 해당 클래스 파일이 BeanDefinition의 구현체로써 생성된다. 이 BeanDefinition인 Bean 메타정보를 바탕으로 스프링컨테이너에 빈이 생성됩니다.

 

추가적으로, SpringContainer는 생성되기 전부터 추상화된 것인 BeanDefinition을 바라보고 있다.(즉, SpringContainer가 BeanDefinition타입의 멤버 변수를 가지고 있다는 이야기..) 이에  xml파일, 자바기반 파일, 어노테이션 기반파일 중 어느 것이 들어오더라도 BeanDefintion의 구현체들로써 만들어지기에 SpringContainer가 Bean을 생성할 수 있게 되는 것이다.

 

만약 어노테이션 기반 파일이 들어왔다고 가정하고, 수동등록에 해당하는 것으로 @configuration과 @Bean 어노테이션을 썻다고 가정하자.

 

위의 가정이라면, 별도 스프링 설정파일을 사용하는 것으로,

1. @Configuration으로 Config 클래스임을 스프링에게 알려준다

2. 그러면, 스프링은 아 이건 Config 클래스구나 빈 등록할 때 CGLIB 기술로 바이트 조작해서 @Bean

     으로 설정되어있는 놈들은 싱글톤 보장하게 바꿔야겠다고 받아들인다.

 

즉, @Configuration이 붙은 클래스를 CGLIB를 통한 래퍼클래스로 생성하고, @Bean이 붙은 메서드들의 내부 의존관계 설정 로직에 대해서 추가적인 로직이 동작하며 의존관계에서 생성되는 객체들도 싱글톤을 보장해준다.

 

따라서 BeanDefinition의 구현체로 만들어지는 순간은 AnnotationConfigApplicationContext의 파라미터로 전달 받은 후 이며, 이 안에는 Bean으로 설정한 것들이 있어 설정한 것들을 싱글톤을 보장하여 객체를 생성한다.

 

※ @Bean당 각 1개씩 메타 정보가 생성된다.


어노테이션 정리

@Component

클래스 레벨에서 선언함으로써 스프링이 런타임시에 컴포넌트스캔을 하여 자동으로 빈을 찾고(detect) 등록하는 애노테이션
@ComponentScan어노테이션으로 인해 해당 클래스가 빈으로 등록이 된다.

@ComponentScan

이 어노테이션이 적용된 해당 클래스의 패키지와 하위 패키지에 있는 @Component 어노테이션 및 @Service, @Repository, @Controller 어노테이션들이 부여된 Class들을 탐색하여 빈으로 등록해주는 어노테이션

 

 

@Configuration 

Bean 메타정보들을 담고 있는 클래스라고 SpringContainer에게 알려주는 어노테이션이다.

즉, 이것이 적용되어 있는 클래스는 이 안에 우리가 관리해야될 빈들이 있다고 SpringContainer에게 알려주는 어노테이션이다

이 어노테이션이 설정된 클래스의 빈들이 싱글톤 방식으로 보장되어야한다는 것을 알려주는 것이기도 하다.

하지만, @Configuration이 적용되어 있는 클래스 역시 빈으로 등록이 되고 관리된다. 

@Bean

메소드 레벨에서 선언하며, 반환되는 객체(인스턴스)를 개발자가 수동으로 빈으로 등록하는 애노테이션이다.
해당 메소드가 반환하는 객체를 빈으로 등록해준다.

 


스프링으로써 빈 등록시 자동 방식과 수동 방식으로 나뉜다.

@Configuration + @Bean(수동 방식) VS @ComponentScan + @Component(자동 방식)

@Configuration + @Bean(수동 방식) 

 AppConfig.class에 @Configuration을 적용했다면, 수동으로 각 @Bean어노테이션을 적용할 메서드들을 작성해야한다.

수동등록은 Config 클래스안에 @Bean을 추가한 메서드로 직접 빈을 등록하며, 의존성 주입도 여기서 진행한다. 이때 메서드 이름이 빈 이름이 된다.

 

@ComponentScan + @Component(자동 방식)

AppConfig.class에@Configuration을 적용했다면,   @ComponentScan으로 어떤 패키지에서부터 Scan을 시작할 건지 작성하고, 해당 패키지 하위에 @Component으로 설정된 클래스가 있다면 이 클래스들을 SpringContainer에 Bean으로 등록한다.

자동등록은 Config 클래스에 @ComponentScan 을 추가한다. 스프링은 @Component가 붙은 클래스의 객체를 스프링 빈으로 추가하며, 클래스 이름 첫글자를 소문자로 바꾼 것이 빈 이름이 된다.

 

스프링 컨테이너의 큰 2가지 동작

1. 스프링 빈 등록

2. @Autowired 어노테이션을 보고 객체 간 의존 관계이자 연관관계를 자동으로 주입

반응형
Comments