티스토리 뷰

스프링은 POJO 프로그래밍을 손쉽게 할 수 있도록 IoC/DI, AOP, PSA 세 가지 기술을 제공한다.
이 세 가지 모두 스프링이 있기 이전에도 여러 가지 형태로 시도됐고, 발전하고 있던 기술이었다. 다만 스프링은 통일성 있고, 세련된 방법으로 자바 엔터프라이즈 개발의 전 영역에 걸쳐 효과적으로 적용될 수 있도록 프레임워크 형태로 제공한다.


제어의 역전 (IoC)과 의존관계 주입 (DI)

왜 두 개의 오브젝트를 분리해서 만들고, 인터페이스를 두어 느슨하게 결합한 뒤, 실제 사용할 대상은 DI를 통해 외부에서 지정하는걸까? DI 방식이 직접 new 연산자를 사용해서 강한 결합을 쓰는 방법보다 나은 점이 무엇일지 의문을 가져본 적이 있을 것이다. 바로 유연한 확장이 가능하게 하기위해서 라고 할 수 있다. DI는 개방 폐쇄 원칙(OCP)이라는 객체지향 설계 원칙으로 설명될 수 있다.


유연한 확장이라는 장점은 OCP의 "확정에는 열려있다(개방)"에 해당하고, DI는 OCP의 "변경에는 닫혀있다(폐쇄)"라는 말로 설명 가능하다. 폐쇄 관점에서 볼 때 장점은 재사용이 가능하다고 볼 수 있다.


만약 A->B라는 의존관계를 갖는 오브젝트 구조가 있을 때, B가 변경돼도 A는 아무런 영향을 받지 않고 그대로 유지 가능하다는 뜻이기도 하다. B 관점에서는 유연한 확장이고 A 관점으로 보자면 변경 없이 재사용이 가능하다고 볼 수 있는 것이다. B가 C로 구현 방식이 바뀌어도 A는 아무런 변경 없이 재사용이 가능하다고 볼 수 있다.


DI 활용 방법

핵심 기능의 변경

DI의 가장 대표적인 적용 방법은 바로 의존 대상의 구현을 바꾸는 것이다. 전략 패턴이 그 대표적인 예이다.
서비스 오브젝트가 사용하는 Repository의 구현체를 JDBC에서 MyBatis, 하이버네이트, JPA 등으로 변경하거나, 사용자의 등급에 따라 지급되는 포인트를 결정하는 정책을 담은 코드를 DI로 분리할 수도 있다. 만약 비지니스 로직이 변경돼서 새로운 등급 정책을 적용해야 한다면, DI를 이용해 기존의 정책 클래스에서 새로운 정책의 클래스로 변경해주면 된다. 이렇듯 실제 의존하는 대상이 가진 핵심 기능을 DI 설정을 통해 변경하는 것이 대표적인 DI의 활용 방법이다.


핵심기능의 동적인 변경

두 번째 방법 역시 첫 번째와 비슷하게 의존 오브젝트의 핵심기능 자체를 변경하는 것이다. 하지만 일반적인 DI를 이용한 변경 방법과는 다르게 동적으로 매번 다르게 변경할 수 있다는 점이다. DI는 런타임 시에 동적으로 의존 오브젝트를 연결해주지만, 한 번 DI 되고 난 후로는 변경되지 않는다. 하지만 DI를 잘 활용하면 애플리케이션이 동작하는 중간에 그 의존 대상을 다이나믹하게 변경할 수 있다.
동적인 방식으로 핵심기능을 변경하는 건, 기술적으로 다이나믹 라우팅 프록시나 프록시 오브젝트 기법을 활용한 것으로, 이 역시 DI가 있기 때문에 가능한 것이다.


부가기능의 추가

세 번째 활용 방법은 핵심 기능은 그대로 두고 부가기능을 추가하는 것이다. 데코레이터 패턴을 이용하면 핵심기능과 클라이언트 코드에는 전혀 영향을 주지 않으면서 부가적인 기능을 얼마든지 추가할 수 있다.


인터페이스의 변경

사용하고자 하는 오브젝트가 가진 인터페이스가 클라이언트와 호환되지 않는 경우가 있다. 또는 여러 종류의 인터페이스를 가졌지만 사실은 비슷한 기능을 담당하는 오브젝트를 바꿔가면서 사용하고 싶을 때도 있다. 이렇게 클라이언트가 사용하는 인터페이스와 실제 오브젝트 사이에 인터페이스가 일치하지 않는 경우에도 DI가 유용하다.


A가 C 오브젝트를 사용하려 한다고 해보자. 하지만 A는 원래 B 인터페이스를 사용하도록 만들어져 있고 C는 B 인터페이스를 구현하지 않았다. 이때 A가 DI를 통해 B의 구현 오브젝트를 받도록 만들어져 있다면 B 인터페이스를 구현했으면서 내부에서 C를 호출해주는 기능을 가진 어댑터 오브젝트를 만들어 A에 DI 해주면 A->B(c로 위임)->C처럼 구성된다. 여전히 A는 DI 덕분에 자신의 코드를 수정하지 않아도 된다.


이를 좀 더 일반화하면 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법도 있다. DI의 응용 방법 중 하나이자 스프링의 대표적인 기술로도 분류되는 일관성 있는 서비스 추상화(PSA)가 그런 방법이다. PSA는 클라이언트가 일관성 있게 사용할 수 있는 인터페이스를 정의해두고 DI를 통해 어댑터 역할을 하는 오브젝트를 이용하게 해준다. 이를 통해 다른 인터페이스를 가진 로우레벨의 기술을 변경하거나 확장해가면서 사용할 수 있는 것이다.


템플릿과 콜백

템플릿/콜백 패턴은 DI의 특별한 적용 방법이다. 반복적으로 등장하지만 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분을 분리해서 템플릿과 콜백으로 만들고 이를 DI 원리를 응용해 적용하면 지저분하게 매번 만들어야 하는 코드를 간결하게 만들 수 있다. 콜백을 템플릿에 주입하는 방식으로 동작하게 하는 것은 DI의 원리에 가장 충실한 응용 방법이다. 콜백을 얼마든지 만들어서 사용할 수 있다는 건 개방을 통한 유연한 확장성을 보여주는 것이며, 템플릿은 한 번 만들어두면 계속 재사용할 수 있다는 건 기능의 확장에도 변하지 않는다는 OCP의 폐쇄 원칙에 가장 잘 들어맞는 것이다.


싱글톤과 오브젝트 스코프

DI를 프레임워크로 이용한다는 건 DI 대상 오브젝트를 컨테이너가 관리한다는 의미다. 오브젝트의 생성부터 관계설정, 이용, 소멸에 이르는 전 과정을 DI 컨테이너가 주관하기 때문에 그 오브젝트의 스코프를 자유롭게 제어할 수 있다.


스프링 DI는 기본적으로 오브젝트를 싱글톤으로 만들어서 사용하게 한다. 컨테이너가 알아서 싱글톤을 만들고 관리하기 때문에 클래스 자체는 싱글톤을 고려하지 않고 자유롭게 설계해도 된다는 장점이 있다. 물론 HTTP 요청당 하나의 오브젝트가 만들어지거나, HTTP 세선당 하나씩 오브젝트가 만들어지게 할 수도 있다.


테스트

DI의 중요한 용도는 바로 테스트다. 다른 오브젝트와 협력해서 동작하는 오브젝트를 효과적으로 테스트하는 방법은 가능한 한 고립시키는 것이다. 즉, 다른 오브젝트와의 사이에서 일어나는 일을 테스트를 위해 조작할 수 있도록 만든다. 그리해야 테스트 대상인 오브젝트의 기능에 충실하게 테스트가 가능하다. 자칫 다른 오브젝트와의 협력을 통해 동작하는 기능을 다 허용하고 테스트하다가는 한 번에 수십 개의 오브젝트와 DB, 환경까지 모두 테스트해야 하는 부담을 안을 수 있다. 그래서 테스트할 대상이 의존하는 오브젝트를 테스트를 목적으로 만들어진 mock오브젝트로 대체하면 유용하다.


관점 지향 프로그래밍 (AOP)

객체지향 기술은 매우 성공적인 프로그래밍 방식임에는 틀림없다. 하지만 날이 갈수록 점점 복잡해지는 애플리케이션의 요구조건과 기술적인 난해함을 모두 해결하는데 한계가 있기도 하다. AOP는 바로 이러한 객체지향 기술의 한계와 단점을 극복하도록 도와주는 보조적인 프로그래밍 기술이다. AOP를 사용하면 OOP를 더욱 OOP답게 만들 수 있다.


AOP의 적용 기법

다이나믹 프록시 사용

다이나믹 프록시를 사용하는 방법은 기존 코드에 영향을 주지 않고 부가기능을 적용하게 해주는 데코레이터 패턴을 응용한 것으로, 자바의 객체지향 패턴을 활용한 방법이기 때문에 만들기 쉽고 적용하기 간편하다. 하지만 인터페이스와 DI를 활용하는 데코레이터 패턴 기반이기 때문에 메서드의 호출이 일어나는 저짐에서만 부가기능을 부여할 수 있다는 제약이 있다.


언어의 확장

AspectJ는 강력한 고급 기능을 가진 AOP를 제공한다. AspectJ는 프록시 방식의 AOP에서는 불가능한 다양한 조인 포인트를 제공한다. 메서드 호출뿐만 아니라 인스턴스 생성, 필드 액세스, 특정 호출 경로를 가진 메서드 호출 등에도 부가기능을 제공할 수 있다. 스프링은 프록시 방식의 AOP를 기본으로 하고 있지만, 원한다면 AspectJ를 이용한 AOP로 바꿔서 사용할 수 있지만, 스프링의 특별한 기능 중에는 AspectJ를 꼭 사용해야 하는 것도 있다.


@Aspect AOP


포터블 서비스 추상화 (PSA)

POJO로 개발된 코드는 특정 환경이나 구현 방식에 종속적이지 않아야 한다. PSA는 환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근할 수 있게 해준다. 스프링은 엔터프라이즈 개발에 사용되는 다양한 기술에 대한 서비스 추상화 기능을 제공하고 있다.


엔터프라이즈 개발에 사용되는 기술은 끊임없이 쏟아져 나오고 있다. 표준 기술뿐 아니라 오픈소스 라이브러리, 상용 프레임워크 형태로도 하루가 멀다 하고 새로운 기술이 등장한다. 하지만 기다릴 필요없이 언제든지 필요하면 직접 추상 레이어를 도입하고 일관성 있는 API를 정의해서 시용하면 된다.


서비스 추상화를 위해 필요한 기술은 DI뿐이다. 결국 DI 응용 방법의 한 가지이므로 DI를 적극 활용해서 개발한다면 서비스 추상화는 자연스럽게 만들어 쓸 수 있다. 서비스 추상화는 단지 구체적인 기술에 종속되지 않게 하기 위해서만 사용되는 것이 아니라, 테스트가 어렵게 만들어진 API나 설정을 통해 주요 기능을 외부에서 제어하게 만들고 싶을 떄도 이용할 수 있다.



Reference
이일민. 『토비의 스프링 3.1』. 에이콘출판(주), 2012.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   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
글 보관함