8.4.1 스프링 기술
- 스프링은 POJO 프로그래밍을 손쉽게 할 수 있도록 하는 세 가지 가능기술을 제공함
- IoC/DI
- AOP
- PSA
- 가능기술 세 가지는 객체지향의 설계와 개발원리를 잘 적용하면 자연스럽게 만들어지는 것 이기도 함
- 다만, 스프링은 통일성과 세련된 방법으로 자바 엔터프라이즈 전 영역에 효과적으로 적용될 수 있도록 프레임워크 형태로 제공하고 있음
- 스프링의 기술들은 POJO 기반의 엔터프라이즈 개발을 편리하게 해주는 도구일 뿐임
8.4.1 제어역전(IoC) / 의존관계 주입(DI)
- IoC/DI는 스프링의 가장 기본이되는 기술이자 스프링의 핵심 개발 원칙임
- 나머지 두 가지인 AOP와 PSA도 IoC/DI에 바탕을 두고 있음
- 3대 핵심 기술은 아니지만, 템플릿/콜백 패턴이 적용된 부분도 IoC/DI가 핵심 원리임
- IoC/DI를 사용하는 이유는 유연한 확장 때문임
- 유연한 확장은 개방폐쇄원칙(OCP)라는 객체지향 설계 원칙으로 잘 설명될 수 있음
- 유연한 확장이라는 장점은 OCP의 ‘확장에는 열려있다(개방)’에 해당됨
- DI는 역시 OCP의 ‘변경에는 닫혀있다(폐쇄)’라는 말로 설명할 수 있음
- 폐쇄 관점에서 볼 때 장점은 ‘재사용’임
- A→B라는 의존관계에서 B는 자유롭게 변경이되고, 그 변경이 A에게 영향을 끼치지 않음
- B관점에서 유연한 확장이고, A 관점으로 보자면 변경없이 재사용이 가능한 것임
- DI의 활용 방법은 8개 이상임
- 핵심기능의 변경
- 핵심기능의 동적인 변경
- 부가기능의 추가
- 인터페이스의 변경
- 프록시
- 템플릿과 콜백
- 싱글톤과 오브젝트 스코프
- 테스트
8.4.2 핵심기능의 변경
- DI의 가장 대표적인 적용 방법은 의존 대상의 구현을 바꾸는 것임
- 예를 들어 DAO의 구현을 JDBC, 하이버네이트, JPA 등으로 바꾸는 것임
- 즉, 구현 방식을 통째로 바꾸는 것임
- 사용자 등급을 결정하는 정책을 DI로 분리하고, 정책 변경시 DI의 구현만 바꾸면 됨
8.4.3 핵심기능의 동적인 변경
- 이 역시 의존 오브젝트의 핵심기능 자체를 변경하는 것임
- 단지, 일반적 DI와 달리 동적으로 매번 다르게 변경할 수 있음
- 일반적 DI는 기본적으로 런타임시에 의존 오브젝트를 연결해 주긴 하지만, 일단 DI가 되고 나면 그 이후로 정적인 관계를 맺어 변경되지 않음
- 하지만 DI를 잘 이용하면 애플리케이션이 동작하는 중간에 의존 대상을 동적으로 변경할 수 있음
- 예를 들어 DAO 하나가 여러 개의 Datasource를 의존하게 만들고, 등급에 따라 동적으로 DB 연결 방법을 달리할 수 있음
- 사용자 등급이 VIP일 경우 더욱 빠른 DB를 사용하게 할 수 있음
- 또 다른 예시는, 사용자별로 모두 독립적인 의존 오브젝트를 두게 만들 수 있음
- 한번 로그인한 사용자는 계속 자신만의 오브젝트를 유지하게 하고, 서비스 오브젝트가 이를 DI 받아서 사용하게 할 수 있음
- 핵심적인 기능이 바뀐다기보다는 기능은 같지만, 독립적인 상태 정보를 저장할 수 있는 자신만의 오브젝트를 가질 수 있다는 것임
- 동적인 방식으로 핵심기능 변경을 하는건, 기술적으로 보자면 다이내믹 라우팅이나 프록시 오브젝트 기법을 활용하는 것임
- 이 두 기법을 적용할 수 있는 이유는 DI가 있기 때문임
8.4.4 부가기능의 추가
- 핵심기능은 그대로 둔 채로 부가기능을 추가할 수 있음
- 인터페이스를 통한 의존성을 만들게 되면, 데코레이터 패턴을 적용할 수 있어 쉽게 부가기능을 추가할 수 있음
8.4.5 인터페이스의 변경
- 때로 사용하려는 오브젝트가 가진 인터페이스가 클라이언트와 호환되지 않는 경우가 있음
- 이렇게 클라이언트가 사용하는 인터페이스와 실제 오브젝트 사이의 인터페이스가 일치하지 않을 때 DI가 유용함
- A가 C를 사용하려고 하지만, A는 B 인터페이스를 사용하도록 만들어져 있고 C는 B 인터페이스를 구현하지 않는 경우가 있음
- 이때, B를 구현하면서 내부적으로 C를 호출하는 기능을 가진 어댑터 오브젝트를 만들어 A에 DI 하면 됨
- 결국, A→B(C로 위임)→C처럼 구성됨
- 여전히 A는 DI 덕분에 자신의 코드를 수정하지 않아도 됨
- 이 방식은, 오브젝트 방식의 어댑터 디자인 패턴 응용임
- 이를 더 일반화해서 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록 중간에 인터페이스 어댑터 역활을 하는 방법 서비스 추상화(PSA)임
- 이를 통해 다른 인터페이스를 가진 로우레벨의 기술을 변경하거나 확장해서 사용할 수 있음
8.4.6 프록시
- 프록시 패턴의 전형적인 응용 방법이 있음
- 필요 시점에 실제 사용할 오브젝트를 초기화하고 리소스를 준비하게 해주는 지연로딩(Lazy Loading)을 적용 하려면 프록시가 필요함
- 또한, 원격 오브젝트를 호출할 때 마치 로컬에 있는 것 처럼 호출하는 원격 프록시를 적용할 때도 프록시가 필요함
- 두 가지 모두 DI를 필요로 함
8.4.7 템플릿과 콜백
- 템플릿/콜백 패턴은 DI의 특별한 적용 방법임
- 변하는 부분과 변하지 않는 부분을 분리해서 템플릿과 콜백으로 만들고 DI 원리를 응용해 적용하면 코드를 간결하게 만들 수 있음
- 콜백을 템플릿에 주입하는 방식은 DI 원리에 가장 충실한 응용 방법임
- 콜백을 얼마든지 만들어 사용할 수 있으므로 유연한 확장성임
- 템플릿을 한 번 만들면 재사용할 수 있으므로 OCP에 잘 맞음
8.4.8 싱글톤과 오브젝트 스코프
- DI가 필요한 중요한 이유 중 한 가지는 DI 할 오브젝트의 생명주기를 제어할 수 있다는 것임
- DI를 프레임워크로 이용한다는 것은 DI 대상 오브젝트를 컨테이너가 관리 한다는 것임
- 오브젝트의 생성부터 소멸까지 DI 컨테이너가 주관하기 때문에, 오브젝트 스코프를 자유롭게 제어할 수 있음
- 가장 기본이 되는 스코프는 역시 싱글톤임
- 여러 스레드의 요청 처리 방식은 오브젝트 개수를 제어하는 일이 가장 중요함
- 한정된 리소스에서 요청마다 오브젝트를 만들게 되면 리소스 고갈이 발생하기 때문임
- 전통적인 싱글톤 패턴은 오브제트에 많은 제약을 가하지만, 컨테이너가 관리하는 IoC 방식은 유용함
- 또한, 컨테이너가 알아서 싱글톤으로 관리하기 때문에 싱글톤을 고려하지 않고 설계가 가능함
- 만일 싱글톤이 아닌 임의의 생명주기를 갖느 오브젝트가 필요할 때도, 다양한 스코프를 갖는 오브젝트를 만들어 DI에 사용할 수 도 있음
8.4.9 테스트
- DI의 가장 중요한 용도는 테스트임
- 효과적인 테스트의 방법은 가능한 대사을 고립하는 것임
- 그래야 오브젝트의 기능에 충실하게 테스트가 가능함
- 의존 오브젝트를 대신해서 스텁 또는 목 오브젝트 같은 테스트 대역을 활용하면 유용함
- 이때, DI는 수정자 메소드를 사용해 테스트 대역을 주입할 수 잇어 중요한 역할을 함
8.4.10 애스팩트 지향 프로그래밍(AOP)
- AOP는 OOP 처럼 독립적인 프로그래밍 패러다임이 아님
- AOP는 OOP의 애플리케이션의 요구조건과 기술적 난해함을 해결하도록 도와주는 보조적인 프로그래밍 기술임
- AOP를 사요하면 OOP를 더욱 OOP로 만들 수 있음
- IoC/DI를 이용해 POJO에 선언적인 엔터프라이즈 서비스를 제공할 수 있지만, 일부 서비스는 OOP만으로 POJO의 조건을 유지한 채 적용하기 힘듦
- 이러한 문제를 해결하는데 AOP가 필요함
- AOP의 적용 기법은 크게 두 가지로 분류할 수 있음
- 스프링과 같이 다이내믹 프록시를 사용하는 방법
- 💡 다이내믹 프록시는 리플렉션으로 프록시를 만드는 방법임[6.3.6 참고]
- 자바 언어의 한계를 넘어서는 언어의 확장을 이용한 방법
8.4.11 스프링과 같이 다이내믹 프록시를 사용하는 방법
- 이 방법은 기존 코드에 영향을 주지 않고, 부가기능을 적용하게 해주는 데코레이터 패턴을 응용한 것임
- 자바의 객체지향 패턴을 활용한 방법이기 때문에 만들기 쉽고 적용하기 간편함
- 하지만, 부가기능은 메소드 호출이 발생하는 지점에만 적용할 수 있음
- 인터페이스와 DI를 활용하는 데코레이터 패턴이 기반이기 때문임
- 스프링의 기본적인 AOP 구현하는 방법은 다이내믹 프록시를 이용하는 프록시 AOP 방식임
8.4.12 자바 언어의 한계를 넘어서는 언어의 확장을 이용한 방법
- 대표적으로 AspectJ가 제공하는 AOP 지원 방식임
- AspectJ는 바이트 코드를 조작하기 때문에 메소드 호출 뿐만이 아니라 인스턴스 생성, 필드 액세스, 특정 호출 경로를 가진 메소드 호출 등에서도 부가기능을 제공할 수 있음
- 이런 고급 AOP 기능을 적용하려면 자바 언어와 JDK만으로 불가능 함
- 대신, 별도의 AOP 컴파일러르 이용한 빌드 과정을 거치거나, 클래스가 메모리로 로딩될 때 그 바이트 코드를 조작하는 위빙과 같은 방법을 이용해야 함
- 사용하기 번거롭지만, 프록시 방식의 AOP로는 할 수 없는 작업이 필요할 때는 AspectJ를 사용해야 함
- 스프링은 프록시 방식의 AOP를 기본으로 하고 있지만, 특정 기능에서는 AspectJ를 꼭 사용해야 하는 것도 있음
- AOP 적용 단계는 3 단계가 있음
- 미리 준비된 AOP 이용
- 전담팀을 통한 정책 AOP 적용
- AOP의 자유로운 이용
8.4.13 미리 준비된 AOP 이용
- 스프링이 미리 만들어서 제공하는 AOP 기능을 그래돌 가져다 적용하는 단계임
- 대표적인 AOP는 트랜잭션임
- 스프링에서 트랜잭션만큼 자주 사용되지 않지만 특정 아키텍처를 선택했을 때 사용할 수 있도록 준비된 AOP 기능이 하나 더 있음
- @Configrable 애노테이션을 이용한 도메인 오브젝트에 DI를 자동으로 적용해주는 AOP 기능임
- 도메인 오브젝트를 전용 계층에 두고 접근하는 아키텍처 방식을 따를 때 반드시 필요함
- @Configrable는 AspectJ를 이용한 AOP가 반드시 필요함
8.4.14 전담팀을 통한 정책 AOP 적용
- AOP의 남발은 코드가 예상하지 못한 방식으로 흘러가 심각한 문제를 초래할 수 있음
- 때문에, 특정 가이드라인 및 규칙에 따라 코드를 작성해야 함
- 개발자가 정해진 가이드라인 및 규칙에 따라 작성을 하지 않을 때를 고려한 단계임
- AOP 담당자 관리하에 보안, 로깅, 트레이싱, 성능 모니터링과 같은 정책적으로 적용할 만한 AOP를 이용하는 것임
- 개발자가 가이드라인 및 규칙에 따라 작성을 하지 않을 때, AOP가 유용하게 쓰일 수 있음
8.4.15 AOP의 자유로운 이용
- 개발자 스스로 AOP를 활용할 수 있는 단계임
- 이전 단계에서는 애플리케이션 전체적으로 적용되는 정책 AOP 위주로 했다면, 이제는 개발자가 구현하는 기능에 적용하면 유용한 세부적 AOP를 이용할 수 있음
8.4.16 포터블 서비스 추상화(PSA)
- PSA(Portable Service Abstraction)는 기술 변화에 관계없이 일관된 방식으로 기술에 접근하도록 하는 기술임
- POJO는 기술 및 환경에 종속적이지 않아야 함
- 스프링은 JavaEE를 기본 플랫포므로 하는 자바 엔터프라이즈 개발에 주로 사용됨
- 따라서 JavaEE에 의존적일 수 밖에 없음
- 특정 기술에 종속적이지 않다는 것은 그 기술을 사용하지 않는다는 것이 아닌, POJO 코드가 기술에 직접 노출되어 만들어지지 않는다는 것임
- 직접 스프링이 제공하는 API를 사용하는 경우 추상 API를 이용해 코드를 작성해야 함
- 구체적인 기술과 설정은 XML 파일안에서 지정함
- 스프링의 서비스 추상화의 개념과 장점을 잘 이해했다면 때에 따라 직접 서비스 추상화 기법을 적용할 필요가 있음
- 엔터프라이즈 개발에 사용되는 기술은 끊임없이 새로 만들어지거나 업그레이드 됨
- 보편적인 기술은 다음 버전의 스프링에서 서비스 추상화 대상으로 포함할 가능성이 있음
- 하지만, 굳이 다음 버전의 스프링을 기다릴 필요가 없음
- 직접 추상 레이어를 도입하고 일관성 있는 API를 정의해서 사용하면 됨
- 서비스 추상화를 위해 필요한 기술은 DI뿐임
- 서비스 추상화는 단지 기술에 종속적이지 않게 하기 위해서만 사용되는 것은 아님
- JavaMail과 같은 테스트가 어렵게 만들어진 API나 설정을 통해 주요 기능을 외부에서 제어하게 만들고 싶을 때 이용할 수 있음
'토비의 스프링 정리' 카테고리의 다른 글
토비의 스프링 - 9.1 자바 엔터프라이즈 플랫폼과 스프링 애플리케이션 (0) | 2022.10.27 |
---|---|
토비의 스프링 - 8.5 8장 정리 (0) | 2022.10.26 |
토비의 스프링 - 8.3 POJO 프로그래밍 (0) | 2022.10.26 |
토비의 스프링 - 8.2 스프링의 목적 (0) | 2022.10.26 |
토비의 스프링 - 8.1 스프링의 정의 (0) | 2022.10.26 |