sungwony

[Spring Framework] IoC 메모 본문

development/스프링 프레임워크

[Spring Framework] IoC 메모

일상이상삼상 2018. 7. 1. 21:18

IoC (Inversion Of Control) "제어의 역행"


기존의 개발방식

: 적절한 위치에서 개발자가 개발코드를 이용하여 필요한 객체를 생성해서 사용하는 방식


IoC

: 적절한 위치에서 Container에게 위임하여 처리하는 방식


IoC의 장점

: Container 기능을 제공하여 객체 간의 결합도를 떨어뜨릴 수 있다.


클래스의 결합과 유지보수성


어떤 클래스 A,B,C,D가 있다고 할 때, 클래스 A의 내부에서 B,C,D 클래스를 참조하여 이용한다고 한다면. B,C,D 클래스가 교체되거나 클래스 내부의 코드가 변경되면 A클래스까지 같이 수정되어야 하는 문제가 발생한다. 즉, 클래스의 결합이 강할수록 유지 보수시에 손을 봐야하는 곳이 많아진다.


객체 결합 

설명 

 속성 객체 결합

한 클래스가 다른 클래스의 객체를 속성으로 가지고 내부 메소드에서 그 객체의 메소드를 호출 

 로컬 객체 결합

메소드 안에서 다른 클래스의 객체를선언하여 그 객체의 메소드를 호출하는 결합 

 파라미터 객체 결합

하나의 메소드가 다른 클래스의 객체를 파라미터 값으로 받아들이는 결합 

 반환 객체 결합

한 객체의 메소드를 호출했을 때 다른 타입의 객체가 반환되어 그 객체를 통해 해당 객체의 메소드를 호출하는 결합 

 상속 결합

클래스가 다른 클래스를 상속받는 결합 

 인터페이스 결합

하나의 인터페이스를 한 클래스가 구현하는 경우의 결합 


스프링은 IoC 방식을 통하여 컨테이너가 객체를 생성하고 라이프 사이클을 관리하게 된다. 컨테이너 내부에서 객체를 생성할 때 Factory 패턴을 활용하여 객체의 결합도를 낮추었다. 이를 IoC모듈이라고 한다.


*팩토리패턴


컨테이너


컨테이너의 필요성

1. 컴포넌트 / 오브젝트의 자유로운 삽입(Pluggability)이 가능하도록 하기 위한 Calling Code의 독립성 때문

2. 서비스의 lookup이나 configuration이 일관성을 갖도록 하기 위함

3. 단일화된 서비스의 접근방법을 제공하기 위함 (개발자가 각각 자기 스타일로 싱글톤이나 Factory를 만들어 쓸 필요가 없어야 함)

4. 비지니스 오브젝트에 부가적으로 필요로 하는 각종 Enterprise Service를 제공하기 위해서


EJB에서의 컨테이너

EJB(Enterprise JavaBeans) 엔터프라이즈 어플리케이션 개발을 단순화하고자 하는 객체

장점 : EJB의 선언적 프로그래밍 모델이 트랙잭션이나 보안과 같은 개발의 기반구조에 해당하는 여러 측면들을 단순화

단점 : 배치설명자(deployment descriptor), 홈/리모트 인터페이스 등과 같은 과도한 코드를 강제함으로써 다른 방식으로 복잡해짐.


EJB 대신 J2EE를 써서 개발하면 안될까?

EJB의 비지니스 서비스 Container로서의 특징과 장점들을 포기하기에는 너무나 아까움

잘 구성된 - 완성도 높은 - EJB기반이 아닌 비지니스 서비스 Container를 사용하면 된다

-> 이 Container는 EJB의 단점들을 가지지 않아야 하며, 동시에 EJB의 장점들을 가지고 있어야 한다.


IoC

Spring Framework를 이해하기 위해서 가장 먼저 이해해야 하는 개념

IoC개념이 Container 기능이 됨

마틴 파울러의 경우 Dependency Injection이라는 용어를 사용하기도 하였다.


Lightweight Container

일반 Container처럼 어플리케이션 코드를 관리해 주지만 그 코드 내에 Container에 대한 의존적인 부분들이 필요 없도록 해줌

-> Object가 Container를 알 필요 없도록

Container 내에 오브젝트를 배치(deploy)하기 위한 복잡한 과정이 없음(Container 그 자체로 작고 가벼움)

-> Pure Java이지 J2EE의존적이 아니기 때문에 J2EE를 벗어나 Standalone Java나 Applet에서도 구동 가능

Container에서 동작할 오브젝트가 fine-grained 또는 coarse-grained의 어떤 것도 가능하도록 오브젝트의 배치가 쉽고 단순하며 오버헤드가 없어야 함.


IoC의 유형

Dependency Lookup

Container가 callback을 통해 제공하는 lookup context를 이용해서 필요한 리소스나 오브젝트를 얻는 방식

EjB, Apache Avalon의 구현방법


JNDI 등을 이용하는데 오브젝트간에 Decoupling을 해주는 면에서 장점이 있지만 아래와 같은 문제점이 생김

1. Container 밖에서 실행할 수 없음

2. JNDI 이외의 방법을 사용할 경우 JNDI관련 코드를 오브젝트 내에 일일이 변경해 줘야 함

3. 테스트하기 매우 어려우며, 코드 양이 증가함

4. Strong typed가 아니므로 Object로 받아서 매번 Casting해야 함

   -> Primitive Data Type조차도 Wrapped Calss를 써야 함

5. NamingException같은 Checked Exception을 처리학 위해서 예외 처리구조가 매우 복잡해짐


Dependency Injection

비지니스 오브젝트에 Lookup 코드를 사용하지 않고 Container가 직접 의존구조를 오브젝트에 설정할 수 있도록 지정해 주는 방법


각 오브젝트가 자신이 의존적인 Resource나 Collaborator 객체에 대한 lookup의 책임을 가지지 않게 하는 것으로 대신 Container가 그 일을 담당하고 오브젝트 내에 주입해 줌

-> Object가 컨테이너의 존재 여부도 알 필요가 없기 때문에 lookup과 관련된 코드들이 오브젝트 내에서 완전히 사라지고 컨테이너에 의존적이지 않은 코드를 작성할 수 있음


Setter Injection

JavaBeans의 property 구조를 이용한 방식

Spring Framework가 주로 Setter Injection을 지지하고 있음

오브젝트가 Container에 의해 만들어지고 나서 바로 모든 Dependency들이 Setter 메소드를 통해서 주입됨


장점

1. JavaBeans property 구조를 사용하기 때문에 IDE등에서 개발하기 편리

2. 상속 시 구조가 그대로 전달됨

3. type conversion을 위해서 JavaBean property-editor 기능을 사용할 수 있음

4. Getter 메소드를 통해 현재 Object의 상태정보를 얻어올 수 있음


단점

1. Setting 순서를 지정할 수 없음

2. 모든 필요한 property가 세팅되는 것에 대해서 보장할 수 없음


Constructor Injection

클래스의 생성자를 이용하는 방법

PicoContainer에서 주로 많이 사용하는 방식


Container의 역할

Spring의 가장 기본적인 기능은 Container

어떤 객체를 생성부터 소멸까지 Life Cycle을 관리해 준다는 것 -> SpringIoC모듈 담당

Container에서 어떤 Service를 제공해 준다는 것 -> AOP모듈 담당


Factory Pattern

GoF의 디자인 패턴 중 하나로써, 서로 다른 객체를 공통의 인터페이스를 이용하여 생성함으로써 그 객체를 이용하는 코드에서 생성 객체에 직접 결합되지 않게 하려는 것

반환 가능한 여러 가지 객체들 중 하나의 객체를 생성하여 반환시켜주는 클래스를 Factory 라고 하고 이러한 패턴을 Factory Pattern 이라고 함

Factory Method Pattern과 Abstract Factory Pattern 으로 나뉜다.


Factory Pattern의 이점

1. 객체 생성 역할을 수행하는 클래스를 두면, 클라이언트 코드에서 직접 필요한 객체를 선택하지 않아도 됨

2. 필요 객체가 무엇인지를 상황에 따라 판단하는 부분이 복잡하다거나 객체 생성 전후 공통의 추가 작업이 필요할 때 Factory 클래스에 정의할 수 있음

3. 상황에 따라 필요한 객체를 생성하여 반환시켜 주는데 그 객체들이 전혀 이질적인 것이 아님

- 보통 반환되는 클래스들은 공통의 부모 클래스로 묶이므로 공통의 인터페이스를 가지는 경우가 일반적임



Spring Container


BeanFactory와 ApplicationContext


SpringContainer : Spring Framework에서 Container 기능을 제공해주는 클래스로 Container 객체 또는 Factory 객체라고 부름

Spring Framework의 초기화

Spring Container 객체 생성 

-> Bean들이 등록되어 있는 XML 파일이 읽히게 됨 

-> XML 파일이 등록된 Bean들의 Life Cycle과 Dependency가 관리되기 시작함

: Spring Container들은 결국 Spring IoC 기능을 제공해 준다고 볼 수 있음


BeanFactory

: BeanFactory 인터페이스로 정의

기본적인 의존성 주입을 지원하는 가장 간단한 형태의 Container


ApplicationContext

: ApplicationContext 인터페이스로 정의됨

프로퍼티 파일의 텍스트 메시지를 해석하는 능력이나 어플리케이션 이벤트와 관련된 이벤트 리스너에 발생하는 능력 등과 같은 어플리케이션 프레임워크 서비스를 제공하는 BeanFactory의 개념 위에 구현된 Container


BeanFactory와 ApplicationContext를 초기화시키기 위해 사용되는 클래스들

 컨테이너 클래스

설명 

 XmlBeanFactory 

Resource 객체를 사용해 컨텍스트 정의 파일을 로딩하는 단순한 BeanFactory

 ClassPathXmlApplicationContext

클래스 경로로부터 컨텍스트 정의 파일을 로딩하는 어플리케이션 컨텍스트 

 FileSystemXmlApplicationContext 

파일 시스템으로부터 컨텍스트 정의 파일을 로딩하는 어플리케이션 컨텍스트 

 XmlWebApplicationContext

웹 어플리케이션 컨텍스트로부터 컨텍스트 정의 파일을 로딩하는 어플리케이션 컨텍스트 


BeanFactory 초기화

BeanFactory는 기본적으로 Bean객체의 생성과 소멸을 담당

XML 파일에 등록되어 있는 Bean 객체를 생성함

-> Bean에 필요한 다양한 속성을 설정해 줌

-> 생성된 객체의 Life Cycle을 관리함


BeanFactory 객체는 XmlBeanFactory 클래스를 이용하여 초기화

String resource = "applicationContext.xml"

private BeanFactory cxt = new XmlBeanFactory(new FileSystemResource(resource))


XmlBeanFactory

XML 파일에 기술되어 있는 정의를 바탕으로 Bean을 생성시켜 Spring Framework을 초기화시킴

XmlBeanFactory의 생성자에 XML 파일을 로딩시켜주는 Resource 타입의 객체를 넘겨줌

Resource의 생성자에 이용하고자 하는 Spring 설정파일의 위치를 알려줌


 Resource

설명

 org.springframework.core.io 패키지

 ByteArrayResource

메모리에 있는 바이트 배열로 만들어진 리소스를 표현 

 ClassPathResource 

클래스패스에서 읽는 리소스를 표현 

 DescriptiveResource

실제 읽을 용도가 아닌 리소스에 대한 정보만 담기 위한 리소스 

 FileSystemResource

파일 시스템에서 읽는 리소스 표현 

 InputStreamResource 

입력 스트림으로 넘어오는 리소스 표현 

 UrlResource

URL에서 읽는 리소스를 표현 

 org.springframework.web.portlet.context 패키지

 PortletContextResource

Portlet 컨텍스트에서 읽는 리소스 

 org.springframework.web.context.support 패키지

 ServletContextResource 

서블릿 Context에서 읽는 리소스 표현 


ApplicationContext

Spring Framework의 완전한 능력을 이용할 수 있도록 좀더 다양한 기능을 제공해주기 위해 사용됨

ApplicationContext는 BeanFactory와 유사하나 차이점과 추가적인 기능 때문에 더 많이 사용됨


 

 BeanFactory

ApplicationContext 

유사점 

 Bean 로딩하고 묶어주고 요청에 따라 반환함

차이점 

 getBean()메소드가 호출될 때까지 빈의 생성을 미룸

 -> 빈 팩토리는 모든 빈을 늦게 로딩함

Context 시작하기 전에 모든 싱글턴 빈을 미리 로딩함

-> 미리 로딩함으로써 빈이 필요할 때 즉시 사용할 수 있도록 해줌 

추가기능

국제화(18N)을 지원함

이미지 등과 같은 자원을 로딩하는 범용적인 방법을 제공함

리스너로 등록되어있는 빈에 이벤트를 발행할 수 있음


ApplicationContext 초기화 방법

제공되는 ApplicationContext 클래스 중 하나를 이용하여 초기화시킴

String resource = "spring/IoC/applicationContext.xml";

private ApplicationContext ctx = new ClassPathXmlApplicationContext(resource)


Spring XML 설정

Spring은 XML의 설정 정보를 참조하여 Bean 클래스의 Life Cycle을 관리해주고 여러 가지 Container Service를 제공해주기 때문에 Spring 설정 파일이 꼭 필요하다.

Spring에서 XML 설정 파일이 가장 중요한 이유는? 간단하게 XML 설정 파일 수정만으로 유지보수작업을 가능하게 만들어주기 때문


[ApplicationContext.xml 파일]

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

     xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xsi:schemaLocation="http://www.springframework.org/schema/beans

                       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

</beans>

</xml>


여러 개의 XML 파일을 사용하여 설정.

Spring 설정 파일에 모든 Bean들을 등록시키고 다양한 설정을 하면 XML 파일이 너무 길게 작성되기 떄문에 효과적인 관리를 위해 여러 XML 파일로 나누어 설정하는 것이 효율적


[userService.xml]

<?xml version="1.0" encoding="UTF-8"?>

<beans>

<bean id="userService" class="user.UserserviceImpl"/>

</beans>


[productService.xml]

<beans>

<bean id="productService" class="product.ProductServiceImpl"/>

</beans>


[applicationContext.xml]

<beans>

<import resource="userService.xml">

<import resource="productService.xml'>

</beans>


Spring Bean

SpringFramework에 등록되어 SpringFramework에 의해 Life Cycle 관리가 이뤄지는 클래스

EJB Bean : 과도한 규칙에 의해 작성

Spring Bean : 특정 클래스를 상속받거나 인터페이스를 구현하지 않아도 되게 만들어지며 Life Cycle 관련된 메소드도 작성하지 않아도 됨


Spring에서 Spring Bean 이용 방법

<bean id="userDAO" class="user.dao.UserDAO"/>


<bean>태그의 attribute

id

- Spring에 등록되는 여러 가지 Bean을 식별하기 위한 식별자로 사용

- 자바 명명규칙을 따르는 임의의 이름으로 지정해 주면 됨

class

- 등록하고자 하는 실제 클래스를 정의

- Bean 등록 시 필수 속성