본문 바로가기

컴퓨터공학/Spring framework 분석

개념> 스프링과 Application Context

IOC와 DI를 쓰는 이유

스프링 컨테이너는 객체 생성과 소멸까지 라이프사이클을 관리.
객체 라이프 사이클 관리를위해 IOC 와 DI를 사용.
IOC(Inversion of Control) 제어의 역전?
객체가 다른 객체 생성을 담당하면 다른 객체에 의존성이 생기게 된다. 
의존성이 생기면 수정 사항이 생길 때 모두 수정해야 한다.
따라서 Container가 객체 생성을 담당하고, 

객체는 추상화하여 설계하면 객체 간의 의존성이 줄어들어서 수정사항이 생겨도 영향을 서로 받지 않게 된다. 
Container가 객체를 생성하고 객체를 주입하는 것을 Dependency Injection(DI)라고 한다. 
객체를 생성하고 의존성을주입하는 컨테이너를 IOC Container라고 한다. 
스프링컨테이너, IOC Container, Bean Factory, Application Context.


Bean 과 Application Context 

객체가 언제 생성되고 사라지는지 알 수 없고 제어의 권한은 개발자가 아니라 스프링컨테이너에 있다.
스프링 컨테이너가 만들고 제어하고 관계를 부여하는 객체를 빈이라고 한다.
스프링 컨테이너에서 빈의 제어를 담당하는 객체를 빈 팩토리라고 한다. 
빈 생성과 관계 설정외 추가 기능이 필요한데 스프링은 빈 팩토리를 상속받아 확장한 Application Context를 사용.
애플리케이션 컨텍스트는 별도 설정 정보를 참고하여 IOC를 적용하고 빈 생성, 관계 설정 등 제어 작업을 총괄.
직접 생성하고 관계를 맺어주는 코드는 없다. 설정을 읽어서 처리한다.
대표적으로 @Configuration 어노테이션이 IOC 설정 정보.

Application Context는 직접 오브젝트를 생성하고 관계를 맺어준다.

 

BeanFactory 인터페이스 
: IOC/DI 기본 기능 제공,
getBean()와 같은 Bean 에 대한 기능을 제공.
ApplicationContext를 통해서 접근가능하다.  

ResourceLoader 인터페이스 
: 서버 환경에서 다양한 Resource를 로딩할 수 있게 기능 제공.
ApplicationContext를 통해서 접근가능하다.  

ApplicationContext 인터페이스 
: BeanFactory, ResourceLoader 모든 기능을 상속. Bean을 통한 의존성 관리 뿐만 아니라 AOP 작업도 수행.

 


클라이언트가 필요로 하는 기능을 정의한 세분화된 인터페이스를 통해서

오브젝트를 접근해야 한다는 인터페이스 분리 원칙으로 
각각의 인터페이스를 DI 하여 사용하는 것을 권장한다.
즉, 기능을 인터페이스로 쪼개서 분리하고 필요한 기능만 인터페이스로 상속하여 객체를 주입해서 사용하면 된다.


ApplicationContext 구현체 종류

<<StaticApplicationContext>>
: Bean 설정 메타정보를 담은 BeanDefinition 오브젝트를 이해하기위한 학습 용도로 사용된다.
실전에서는 잘 사용되지 않는다. 단순 컨테이너에서 Bean 등록방식을 확인하는 목적으로 사용된다. 

이 기능을 사용하는 이유를 다시 상기하자.
객체를 context에 빈으로 등록하고 빈을 사용하고 싶을 때 
우리는 context에서 등록된 빈을 호출해서 사용하면 된다. 
우리는 빈을 호출해서 사용하면 되는 것이고 라이프사이클은 context가 알아서 하니 사용하는 것만 집중하면 된다.
싱글톤을 사용하는 거라서 오직 하나만 등록되고 중복은 ㄴㄴ 

예시를 보면 어떤 클래스를 context에 빈으로 등록할 때 이름을 붙여서 등록한다.
registerSingleton("[여기에 이름입력]", [클래스].class)
getBean("[여기에 이름입력]")으로 이름을 써서 부른다. 
이름을 따로 설정할 수 있는데 setName("[여기에 이름 설정]") 으로 할 수 있고  getName( )으로 이름을 호출할 수 있다. 

위에 registerSingleton할 때 [클래스].class 이런 식으로 클래스를 주입할 수 있지만

BeanDefinition 객체로 빈으로 만드는 방법이 있다. 
BeanDefinition 객체를 만들 때 RootBeanDefinition([클래스].class) 로 객체를 만들고 
이 객체의  addPropertyValue("name", "[설정값 입력]") 으로 설정값을 주입하고 
registerSingleton 대신 registerBeanDefinition을 사용하여 에서 BeanDefinition 객체를 주입하면 된다. 
이제 Context에 Bean이 등록이 되었고 등록된 Bean을 사용하고 싶으면 
context.getBean("[여기에 빈 이름 입력]") 해서 사용하면 된다. 

위 내용은 객체를 빈으로 등록하고 호출하는 BeanFactory에 있는 기능이다. 
그렇다면 관계설정은 어떻게 할까? 

context에 빈을 하나 등록한 다음 
다른 beanDefinition 객체에서 .addPropertyValue("[여기에 속성명 입력]", new RuntimeBeanReference("[여기에 빈 이름 입력]"));


<<GenericApplicationContext>>
: 일반적인 ApplicationContext를 실전에서 사용될 수 있는 모든 기능을 갖추고 있다
xml같은 메타 정보를 맞는 XmlBeanDefinitionReader인 리더기로 읽어서 BeanDefinition으로 변환해서 사용한다. 
즉, 1. GenericApplication은 모든 리더기로부터 설정 메타정보를 읽어서 
2. BeanDefinition 오브젝트를 만들고 
3. Bean으로 등록할 수 있다는 뜻이다. 
Generic = 모든 리더기
코드 레벨에서 직접 이용하는 경우는 드문데 주로 테스트를 위한 프레임워크인 JUnit 테스트에서 사용된다.
@ContextConfiguration( ) 어노테이션으로 지정한 경로에서 설정 메타 정보를 읽는다. 

GenericApplicationContext 객체를 XmlBeanDfinitionReader 객체에 넣고 이 객체의 메소드 
.loadBeanDefinitions("[여기에 xml 경로 입력]")
그 다음 GenericApplicationContext 객체 메소드 .refesh() 한 다음 
getBean("[빈 이름 입력]", [빈 클래스].class)하면 된다. 


<<GetnericXmlApplicationContext >>
GenericApplicationContext는 reader를 생성하고 설정파일을 읽어오는 코드까지 사용자가 직접 작성해야 하는 불편함이 있다.
그래서 그 불편함을 없애고자 GenericXmlApplicationContext가 나왔다. 
이 구현체는 reader까지 포함되어 있다. 
세밀한 설정은 GenericApplicationContext를 사용하면 된다. 
new GenericXmlApplicationContext("[여기에 xml 경로 입력]") 하여 객체를 만들고  
이걸로 getBean("[여기에 빈 이름 입력]") 하면 된다. 

<<WebApplicationContext>>
ApplicationContext를 확장한 인터페이스이다. ( getServletContext() 메서드가 추가된 인터페이스이다.) 
웹 환경에서 사용할 때필요한 기능이 추가된 ApplicationContext이다. 
XmlWebApplicationContext, AnnotationConfigWebApplication 등을 사용하고 기본값은 XmlWebApplicationContext

 

 

 

WebApplicationContext 작동법

IOC가 적용된 Application을 작동하는 방법은 초기화된 ApplicationContext 메소드(getBean와 같은)를 호출하는 것이다.
프로그래밍에서 초기화란 데이터 오브젝트나 변수의 초기값 할당을 의미한다.
자바에서 초기화는 객체를 선언하고 값을 최초로 할당하는 것이다. 
선언과 동시에 초기화하고 그 이후에 입력하면 초기화가 아니라 값을 바꾸는 할당이 된다. 


(초기화란 무엇인가? http://wiki.hash.kr/index.php/%EC%B4%88%EA%B8%B0%ED%99%94 )

 

따라서  Application 객체를 선언하고 초기 설정하는 한 다음 getBean 메소드를 호출해야 되는데 
지금 까지 사용한 방법은 main 함수 안에서 초기화한 방법이다. 

그러나 웹 환경은 main 함수 호출이 쉽지 않다.
그래서 웹 환경에서 main 함수를 대체하는 얘가 DispatcherServlet이라는 얘이다. 

 

DispatcherServlet은 미리 초기화된 ApplicationContext 빈정보를 가져오고 

클라이언트 요청이 있으면 미리 받아온 빈 정보를 이용하여 메소드를 호출한다.
즉, DispatcherServlet이 빈을 호출한다. 이런 식으로 Application이 실행되는 것이다. 

 

정리하자면 개발자는 필요할 때 호출만 하면 되는 것이다. 
객체 초기화 생성 주입은 스프링 컨테이너가한다.
이것을 IOC(Inversion of Control) 제어의 역전이다. 

 

 

(다양한 ApplicationContext 예제와 실제 사용되는 예시 

https://coding-start.tistory.com/48 

 

다양한 ApplicationContext 예제 및 소개

1.StaticApplicationContext -코드를 통해 빈 메티정보를 등록하기 위해 사용한다. 거의 사용되지 않는 구현체이다. 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 32  ..

coding-start.tistory.com