이 글은 “토비의 스프링” 책 내용을 정리한 글입니다.

만약 저작권 관련 문제가 있다면 “gunjuko92@gmail.com”로 메일을 보내주시면, 바로 삭제하도록 하겠습니다.

토비의 스프링 - 스프링이란 무엇인가?

스프링은 단순히 IoC/DI를 편하게 적용하도록 돕는 단계를 넘어서 엔터프라이즈 애플리케이션 개발의 전 영역에 걸쳐 다양한 종류의 기술에 관여한다.

1. 스프링의 정의

  • 스프링에 대해 가장 잘 알려진 정의 : 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크

애플리케이션 프레임워크

  • 프레임워크는 애플리케이션의 특정 계층에서 주로 동작하는 한 가지 기술 분야에 집중된다. 하지만 스프링은 이와 다르게 ‘애플리케이션 프레임워크’라는 특징을 갖고 있다.
  • 애플리케이션 프레임워크는 특정 계층이나 기술 업무 분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 범용적인 프레임워크를 말한다.
  • 애플리케이션 프레임워크는 애플리케이션 개발의 전 과정을 빠르고 편리하며 효율적으로 진행하는데 일차적인 목표를 두는 프레임워크다.
  • 스프링의 탄생배경
    • 스프링은 로드 존슨이 쓴 책의 예제 코드에서 시작했다.
    • 스프링의 기원이 된 예제 애플리케이션의 프레임워크는 책에서 설명한 각종 자바 엔터프라이즈 개발 전략의 핵심을 담아서 개발됐다. 이 책 자체가 자바 엔터프라이즈 개발의 전 계층에 등장하는 기술과 애플리케이션의 전 영역에 대한 효과적인 설계와 개발 기법을 다루고 있었기 때문에 예제 프레임워크 또한 애플리케이션 전반에 걸친 모든 분야를 포괄하고 있었다.
    • 예제 프레임워크로부터 시작된 스프링은 자연스럽게 애플리케이션의 전 영역을 지원하는 종합적인 애플리케이션 프레임워크가 되었다.
  • 애플리케이션의 전 영역을 관통하는 일관된 프로그래밍 모델과 핵심 기술을 바탕으로 해서 각 분야의 특성에 맞는 필요를 채워주고 있기 때문에, 애플리케이션을 빠르고 효과적으로 개발할 수가 있다. 바로 이것이 스프링이 애플리케이션 프레임워크라고 불리는 이유다.

스프링을 MVC 프레임워크 또는 JDBC/ORM 지원 프레임워크라고 생각하는 것은 스프링이 다루는 일부 영역만봤기 때문이다. 또, 스프링을 IoC/DI 프레임워크나 AOP 툴이라고 보는 이유는 스프링이 제공하는 핵심 기술에만 주목했기 때문이다. 스프링의 일차적인 존재 목적은 핵심 기술에 담긴 프로그래밍 모델을 일관되게 적용해서 엔터프라이즈 애플리케이션 전 계층과 전 영역에 전략과 기능을 제공해줌으로써 애플리케이션을 편리하게 개발하게 해주는 애플리케이션 프레임워크로 사용되는 것 임을 기억해두자.

경량급

  • 스프링이 경량급이라는 건 스프링 자체가 아주 가볍다거나 작은 규모의 코드로 이뤄졌다는 뜻은 아니다.
  • 스프링이 가볍다고 하는 이유는 스프링은 불필요하게 무겁지 않다는 의미다. 스프링과 대조되는 대표적인 프레임워크는 EJB이다.
  • 스프링은 가장 단순한 서버환경인 톰켓이나 제티에서도 완벽하게 동작한다. 서블릿 컨테이너만으로 충분하니 EJB 컨테이너를 비롯해 복잡한 기능이 잔뜩 포함된 고급 WAS를 굳이 사용하지 않아도 된다.
  • 스프링은 EJB를 대표로 하는 기존의 많은 기술이 불필요하게 무겁고 복잡했음을 증명한 셈이고 그런 면에서 스프링은 군더더기 없이 깔끔한 기술을 가진 “경량급” 프레임워크라고 불린 것이다.
  • 스프링 기반의 코드가 가벼운 이유는 코드에 불필요하게 등장하던, 프레임워크와 서버환경에 의존적인 부분을 제거해주기 때문이다. EJB와 WAS 같은 기술과 환경을 지원하기 위해 군더더기처럼 우겨넣어야 했던, 판에 박힌 듯이 반복되던 코드가 제거되고 나니 가장 단순하고 가벼운 코드만 남게 됐다.

만들어진 코드가 지원하는 기술 수준은 비슷하더라도 그것을 훨씬 빠르고 간편하게 작성하게 해줌으로써 생산성과 품질 면에서 유리하다는 것이 바로 경량급이라는 말로 표현되는 스프링의 특징이다.

자바 엔터프라이즈 개발을 편하게

  • 스프링은 근본적인 부분에서 엔터프라이즈 개발의 복잡함을 제거해내고 진정으로 개발을 편하게 해주는 해결책을 제시한다.
  • 엔터프라이즈 개발의 근본적인 문제점에 도전해서 해결책을 제시한다는 것이 기존 기술의 접근 방법과 스프링의 접근 방법의 차이점이다.
  • 편리한 애플리케이션 개발이란 개발자가 복잡하고 실수하기 쉬운 로우레벨 기술에 많은 신경을 쓰지 않으면서도 애플리케이션의 핵심인 사용자의 요구사항, 즉 비즈니스 로직을 빠르고 효과적으로 구현하는 것을 말한다.
  • 스프링은 애플리케이션 개발자들이 스프링이라는 프레임워크가 제공하는 기술이 아니라 자신이 작성하는 애플리케이션의 로직에 더 많은 관심과 시간을 쏟게 해준다.
  • 스프링은 또한 엔터프라이즈 개발의 기술적인 복잡함과 그에 따른 수고를 제거해준다. 여기서 제거한다는 건 그런 기술적인 필요를 무시한다는 의미는 아니다. 엔터프라이즈 개발에서 필연적으로 요구되는 기술적인 요구를 충족하면서도 개발을 복 잡하게 만들지 않는다는 점이 스프링의 뛰어난 면이다.

오픈 소스

  • 스프링은 오픈소스 프로젝트 방식으로 개발돼왔다. 지금도 여전히 오픈소스 개발 모델과 오픈소스 라이선스를 가지고 개발되는 중이며, 이 사실은 앞으로도 바뀌지 않을것 이다.

2. 스프링의 목적

  • 스프링도 목적을 바로 이해하고 그 목적을 이루는 도구로 스프링을 잘 활용해야만 스프링으로부터 제대로 된 가치를 얻을 수 있다. 어떤 기술이든 그 자체로는 도구에 불과하다. 그것을 용도에 맞게 잘 활용해서 궁극적으로 이루고자 하는 목표를 이루는 것이 중요하지 도구의 사용법만 열심히 익힌다고 결과를 저절로 얻을수 있는건 아니다.
  • 스프링의 목적은 무엇인가? 경량급 프레임워크인 스프링을 활용해서 엔터프라이즈 애플리케이션 개발을 편하게 하는것이다.

2.1 엔터프라이즈 개발의 복잡함

엔터프라이즈 시스템 개발은 왜 복잡할까? 크게 두 가지 원인을 생각해볼 수 있다.

첫 번째는 기술적인 제약조건과 요구사항이 늘어가기 때문이다.

  • 엔터프라이즈 시스템은 뛰어난 성능과 서비스의 안정성이 요구되고 그런 점을 고려한 개발 기술이 필요하다. 즉 엔터프라이즈 시스템을 개발하는데는 순수한 비즈니스 로직을 구현하는 것 외에도 기술적으로 고려할 사항이 많다는 뜻이다.
  • 기술적인 문제를 고려하면서 애플리케이션을 개발해야 하는 부담을 안게 된다.

두 번째는 엔터프라이즈 애플리케이션이 구현해야 할 핵심기능인 비즈니스 로직의 복잡함이 증가하기 때문이다.

  • 다양하고 복잡한 업무 처리 기능을 엔터프라이즈 시스템이 구현해야 했다. 엔터프라이즈 시스템이 관여하는 업무의 비율이 급격하게 커지고 있으니 당연히 애플리케이션 개발도 힘들고 복잡해져 가는 것이다.

복잡함을 가중시키는 원인

  • 자바 엔터프라이즈 시스템 개발이 어려운 가장 큰 이유는 근본적인 비즈니스 로직과 엔터프라이즈 기술이라는 두 가지 복잡함이 한데 얽혀 있기 때문이다. 하나씩 놓고 봐도 만만치 않은데, 그 두 가지를 한 번에 다뤄야 하니 복잡함이 몇 배로 가중되는것이다.
  • 각종 엔터프라이즈 기술 서비스를 적용하기 위한 코드와 각종 기술적인 API의 호출 코드를 비즈니스 로직에 대한 구현코드와 함께 덕지덕지 붙여서 만드는것은 매우 어렵다.
  • 더 큰 문제는 그렇게 기술과 비즈니스 로직의 복잡함에 엉켜 있는 코드를 유지보수하는 일이다.

2.2 복잡함을 해결하려는 도전

제거될 수 없는 근본적인 복잡함

  • 엔터프라이즈 개발에 나타나는 복잡함의 원인은 제거 대상이 아니다. 대신 그 복잡함을 효과적으로 상대할 수 있는 전략과 기법이 필요하다. 문제는 비즈니스 로직의 복잡함을 효과적으로 다루기 위한 방법과 기술적인 복잡함을 효과적으로 처리하는데 적용되는 방법이 다르다는 점이다. 따라서 두 가지 복잡함이 코드에 한데 어우러져 나타나는 전통적인 개발 방식에서는 효과적으로 복잡함을 다루기가 힘들다.
  • 가장 먼저 할 일은 성격이 다른 이 두 가지 복잡함을 분리해내는 것이다.

실패한 해결책 : EJB

  • 애플리케이션 로직을 담은 핵심 코드에서 일부 기술적인 코드가 제거된 건 사실이지만, 오히려 EJB라는 환경과 스펙에 종속되는 코드로 만들어져야 하는 더 큰 부담을 안게 됐다.
  • EJB는 결국 일부 기술적인 복잡함을 덜어주려는 시도를 하다가 오히려 더 큰 복잡함을 추가하는 실수를 범했다.

비침투적인 방식을 통한 효과적인 해결책: 스프링

  • EJB의 처음 목표와 마찬가지로 기술적인 복잡함을 애플리케이션 핵심 로직의 복잡함에서 제거하는데 목표를 뒀다. 하지만 그 과정에서 EJB처럼 개발자의 코드에 난입해서 지저분하고 복잡한 코드를 만들어버리는 실수를 하지는 않았다.
  • 침투적인 기술 : EJB처럼 어떤 기술을 적용했을 때 그 기술과 관련된 코드나 규약 등이 코드에 등장한 경우
    • 꼭 필요한 기능을 사용하는것도 아니면서, 단지 어떤 기술을 바탕으로 만들어진다고 해서 특정 클래스나 인터페이스 API 등의 코드에 마구 등장한다면 그것은 침투적인 기술이 되며 복잡함을 가중시키는 원인이 된다.
  • 비침투적인 기술 : 기술의 적용 사실이 코드에 직접 반영되지 않는다는 특징이 있다. 어딘가에는 기술의 적용에 따라 필요한 작업을 해줘야 하겠지만, 애플리케이션 코드 여기저기에 불쑥 등장하거나, 코드의 설계와 구현 방식을 제한하지는 않는다는 게 비침투적인 기술의 특징이다.
  • 스프링이 성공할 수 있었던 비결은 바로 비침투적인 기술이라는 전략을 택했기 때문이다. 스프링을 이용하면 기술적인 복잡함과 비즈니스 로직을 다루는 코드를 깔끔하게 분리할 수 있다. 중요한 점은 그 과정에서 스프링 스스로가 애플리케이션 코드에 불필요하게 나타나지 않도록 하는 것이다. 꼭 필요할 것 같은 경우조차도 기술 코드가 직접 노출되지 않도록 만들어줬다.

2.3 복잡함을 상대하는 스프링의 전략

  • 스프링의 기본적인 전략은 비즈니스 로직을 담은 애플리케이션 코드와 엔터프라이즈 기술을 처리하는 코드를 분리시키는 것이다. 이 분리를 통해 두 가지 복잡함의 문제를 효과적으로 공략하게 해준다.

기술적 복잡함을 상대하는 전략

첫번째문제 : 기술에 대한 접근방식이 일관성이 없고, 특정 환경에 종속적이다.

  • 환경이 바뀌고, 서버가 바뀌고, 적용되는 조건이 바뀌면 적용하는 기술이 달라지고 그에 따라 코드도 바뀐다는 건 심각한 문제다.
  • 목적이 유사하지만 호환이 안되는 표준, 비표준, 오픈소스 상용제품 등이 제공하는 각기 다른 API를 사용하도록 코드를 일일이 변경해야하는 번거로움이 발생한다.
  • 일관성 없는 기술과 서버환경의 변화에 대한 스프링의 공략 방법은 바로 서비스 추상화다. 앞에서 살펴봤던 트랜잭션 추상화나 OXM 추상화, 데이터 액세스에 관한 일관된 예외변환 기능, 데이터 액세스 기술에 독립적으로 적용 가능한 트랜잭션 동기화 기법 등이 그런 대표적인 예다.
  • 기술적인 복잡함은 일단 추상화를 통해 로우레벨의 기술 구현 부분과 기술을 사용하는 인터페이스를 분리하고, 환경과 세부 기술에 독립적인 접근 인터페이스를 제공하는 것이 가장 좋은 해결책이다.
  • 데이터 액세스 예외에 대한 추상화는 비즈니스 로직을 담은 서비스 레이어의 코드가 특정 기술이 발생시키는 예외에 종속되지 않고 불필요하게 예외를 잡아야 하거나 throws를 선언해야 하는 것을 방지해준다.
  • 스프링이 제공하는 탬플릿/콜백 패턴은 판에 박힌 반복적인 작업 흐름과 API 사용 코드를 제거해준다. 이를 통해 기술을 사용하는 코드도 최적화된 핵심 로직에만 집중하도록 도와준다.

두 번째 문제 : 기술적인 처리를 담당하는 코드가 성격이 다른 코드에 섞여서 등장한다.

  • 기술과 비즈니스 로직의 혼재로 발생하는 복잡함을 해결하기 위한 스프링의 접근 방법은 바로 AOP다.
  • AOP는 최후까지 애플리케이션 로직을 담당하는 코드에 남아 있는 기술 관련 코드를 깔끔하게 분리해서 별도의 모듈로 관리하게 해주는 강력한 기술이다.
  • AOP는 기술을 다루는 코드로 인한 복잡함이 기술 그 자체 이상으로 불필요하게 증대되지 않도록 도와주는 가장 강력한 수단이다.

비즈니스와 애플리케이션 로직의 복잡함을 상대하는 전략

  • 비즈니스 로직은 가장 중요하게 다뤄져야 하고 가장 많이 신경 써야 한다.
  • 전에는 비즈니스 로직의 상당 부분을 DB에 두는 것이 유행이었다. SQL을 통해 비즈니스 로직을 표현하고, DB에서 동작하는 저장 프로시저를 통해 핵심 로직을 처리하는 경우도 많았다.
  • 엔터프라이즈 시스템의 규모가 커지고 복잡함이 증가하면서 DB에 비즈니스 로직을 두는건 매우 불편할뿐더러 위험한 일이라고 여겨지기 시작했다. 가장 확장하기 힘들고 확장하더라도 많은 비용이 드는 공유 자원인 DB에 커다란 부담을 주는 것도 문제고, 데이터 액세스를 중심으로 로직을 다루면 개발과 유지보수는 물론이고 테스트도 매우 어렵다.
  • 엔터프라이즈 시스템 개발의 흐름은 점차 비즈니스 로직은 애플리케이션 안에서 처리하도록 만드는 추세다. DB는 단지 데이터의 영구적인 저장과 복잡한 조건을 가진 검색과 같은 자체적으로 특화된 기능에만 활용하고, 데이터를 분석하고 가공하고 그에 따라 로직을 처리하는 부분은 확장하기 쉽고, 비용도 싼 애플리케이션 서버 쪽으로 이동하는 것이다.
  • 오브젝트에 담긴 로직은 테스트하기도 쉽다. 목 오브젝트 등을 이용하면 심지어 DB가 없어도 테스트를 할 수 있다. 게다가 CBD를 비롯한 최신 설계와 개발 기법, 모델링을 중심으로한 개발 방법은 오브젝트 기반의 설계와 구현에 잘 들어 맞는다.
  • 객체지향 프로그래밍 기법과 언어가 주는 장점인 유연한 설계가 가능하고 재사용성이 높다는 점을 잘 활용하면 자주 바뀌고 조건이 까다로운 비즈니스 로직을 효과적으로 구현해낼 수 있다.
  • 환경에 종속적인 기술과 침투적인 기법으로 인해 추가된 군더더기에 방해만 받지 않는다면 객체지향 언어로서의 장점을 잘 살려 비즈니스 로직의 복잡함을 최대한 효과적으로 다룰 수 있는 깔끔한 코드를 만드는 건 어렵지 않다.
  • 비침투적인 기술인 스프링은 핵심 로직을 다루는 코드에는 (특별한 이유가 없다연) 스프링의 흔적조차 찾을 수 없을 만큼 자신을 드러내지 않는다. 다만 뒤에서 비즈니스 로직을 담당하는 오브젝트들에게 적절한 엔터프라이즈 기술 서비스가 제공되도록 은밀히 도와줄 뿐이다.

결국 비즈니스 로직의 복잡함을 상대하는 전략은 자바라는 객체지향 기술 그 자체다. 스프링은 단지 객체지향 언어의 장점을 제대로 살리지 못하게 방해했던 요소를 제거 하도록 도와줄 뿐이다.

핵심 도구: 객체지향과 DI

  • 기술과 비즈니스 로직의 복잡함을 해결하는데 스프링이 공통적으로 사용하는 도구는 바로 객체지향이다.
  • 스프링의 모토는 결국 “기본으로 돌아가자”이다. 자바의 기본인 객체지향에 충실한 설계가 가능하도록 단순한 오브젝트로 개발할 수 있고 객체지향의 설계 기법을 잘 적용할 수 있는 구조를 만들기 위해 DI 같은 유용한 기술을 편하게 적용하도록 도와주는것이 스프링의 기본 전략이다.
  • DI란 특별한 기술이라기보다는 유연하게 확장할 수 있는 오브젝트 설계를 하다 보면 자연스럽게 적용하게 되는 객체지향 프로그래밍 기법일 뿐이다. 스프링은 단지 그것을 더욱 편하고 쉽게 사용하도록 도와줄 뿐이다.
  • DI를 의식하다 보면 오브젝트를 설계할 때 자주 DI를 적용할 후보가 더 이상 없을까를 생각해보게 된다. 여기서 바뀔 수 있는 것은 무엇일까? 여기서 성격이 다르고, 변경의 이유가 다른 기능은 무엇일까? 그리고 그런 후보를 찾을 수 있다면 DI를 적용해서 오브젝트를 분리하고 인터페이스를 도입하고 DI로 관계를 연결해줄것이다.
  • Dl는 좋은 오브젝트 설계의 결과물이기도 하지만, 반대로 Dl를 열심히 적용하다 보면 객체지향 설계의 원칙을 잘 따르고 그 장점을 살린 설계가 나올 수도 있다.
  • 객체지향과 Dl는 서로 떼놓고는 생각할 수 없다. 만약 스프링을 사용하고 Dl를 적용했다고 하지만, 기계적인 방법으로 항상 사용하는 틀에 박힌 구조의 빈만 정의하고 나머지 코드에는 Dl를 적용해볼 생각조차 안 한다면 Dl를 잘못 사용하고 있는것이다.
  • 기술적인 복잡함을 해결하는 문제나 기술적인 복잡함이 비즈니스 로직에 침범하지 못하도록 분리하는 경우에도 Dl가 바탕이 된 여러 가지 기법이 활용된다. 반면에 비즈니스 로직 자체의 복잡함을 해결하려면 Dl보다는 객체지향 설계 기법이 더 중요하다.
  • 객체지향적인 특성을 잘 살린 설계는 상속과 다형성, 위임을 포함해서 많은 객체지향 디자인 패턴과 설계 기법이 잘 녹아들어 갈 수 있다. 기술적인 코드에 침범당하지 않았다면 이런 설계를 비즈니스 로직을 구현하는 코드에 그대로 반영할 수 있다.
  • 모든 스프링의 기술과 전략은 객체지향이라는 자바 언어가 가진 강력한 도구를 극대화해서 사용할 수 있도록 돕는 것이라고 볼 수 있다. 스프링은 단지 거들 뿐이다.

스프링만 잘 공부하면 자바 언어 자체나 객체지향 설계와 개발 실력 따윈 별로 신경 쓰지 않아도 복잡한 엔터프라이즈 시스템 개발을 잘할 수 있을거라고 생각하면 오산이다.

3. POJO 프로그래밍

  • 스프링의 정수는 엔터프라이즈 서비스 기능을 POJO에 제공하는 것
  • 엔터프라이즈 서비스라고 하는 것은 보안, 트랜잭션과 같은 엔터프라이즈 시스템에서 요구되는 기술을 말한다. 이런 기술을 POJO에 제공한다는 말은 뒤집어 생각해보면 엔터프라이즈 서비스 기술과 POJO라는 애플리케이션 로직을 담은 코드를 분리했다는 뜻이기도 하다. 분리됐지만 반드시 필요한 엔터프라이즈 서비스 기술을 POJO 방식으로 개발된 애플리케이션 핵심 로직을 담은 코드에 제공한다는 것이 스프링의 가장 강력한 특징과 목표다.

3.1 스프링의 핵심 POJO

스프링의핵심

  • 위 그림은 스프링으로 개발한 애플리케이션의 기본 구조를 보여준다. 스프링 애플리케이션은 POJO를 이용해서 만든 애플리케이션 코드와 POJO가 어떻게 관계를 맺고 동작하는지를 정의해놓은 설계정보로 구분된다.
  • 스프링의 주요 기술인 IoC/DI, AOP와 Portable Service Abstraction는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능 기술(enabling technology)이라고 불린다.

3.2 POJO란 무엇인가?

  • POJO : Plain Old Java Object의 첫 글자를 따서 만든 약자다.
  • POJO라는 단어를 만든 마틴 파울러는 자바의 단순한 오브젝트를 이용해 애플리케이션의 비즈니스 로직을 구현하는 편이 낫다고 생각했다.

3.3 POJO의 조건

적어도 다음의 세 가지 조건을 충족해야 POJO라고 불릴 수 있다.

  • 특정 규약에 종속되지 않는다.
    • 특정 규약에 따라 비즈니스 컴포넌트를 만들어야 하거나, 특정 클래스를 상속해서 만들어야하는 경우는 POJO가 아니다.
    • 특정 클래스를 상속해서 만들어야하는 경우, 자바의 단일 상속 제한 때문에 클래스에 객체지향적인 설계 기법을 적용하기가 어려워지는 문제가 생긴다.
    • 규약이 적용된 환경에 종속적이 되기 때문에 다른 환경으로 이전이 힘들다는 문제점이 있다.
  • 특정 환경에 종속되지 않는다.
    • 특정 환경에 종속적이어야만 동작하는 오브젝트도 POJO라고 할 수 없다.
    • 순수한 애플리케이션 로직을 담고 있는 오브젝트 코드가 특정 환경에 종속되게 만드는 경우라면 그것 역시 POJO라고 할 수 없다. 예들 들면 WebLogic 서버에서만 사용 가능한 API를 직접 쓴 코드를 갖고 있거나 특정 OS에서 제공하는 기능을 직접 호출하도록 만들어진 오브젝트 등
    • 비즈니스 로직을 담고 있는 POJO 클래스는 웹이라는 환경정보나 웹 기술을 담고 있는 클래스나 인터페이스를 사용해서는 안 된다. 설령 나중에는 웹 컨트롤러와 연결돼서 사용될 것이 뻔하다고 할지라도 직접적으로 웹이라는 환경으로 제 한해버리는 오브젝트나 API에 의존해선 안 된다.
    • 비즈니스 로직을 담은 코드에 HttpServletRequest나 HttpSession, 캐시와 관련된 API가 등장하거나 웹 프레임워크의 클래스를 직접 이용하는 부분이 있다면 그것은 진정한 POJO라고 볼 수 없다.
    • 애노테이션이 단지 코드로 표현하기는 적절치 않은 부가적인 정보를 담고 있고, 그 때문에 환경에 종속되지만 않는다면 여전히 POJO라고 할 수 있다. 하지만 애노태이션이나 엘리먼트 값에 특정 기술과 환경에 종속적인 정보를 담고 있다면 그때는 POJO로서의 가치를 잃어버린다고 할 수 있다.
  • POJO는 객체지향적인 자바 언어의 기본에 충실하게 만들어져야 한다.
    • 책임과 역할이 각기 다른 코드를 한 클래스에 몰아넣어 덩치 큰 만능 클래스로 만드는 경우, 재사용이 불가능할 정도로 다른 레이어와 영역의 코드와 강한 결합을 가지고 만들어지는 경우, 상속과 다형성의 적용으로 처리하면 깔끔한 것을 if/switch문이 가득 찬 길고 긴 메소드로 작성해놓은 경우라면 POJO가 아니다.

진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다. 그런 POJO에 애플리케이션의 핵심 로직과 기능을 담아 설계하고 개발하는 방법을 POJO 프로그래밍이라고 할 수 있다.

3.4 POJO의 장점

  • 특정한 기술과 환경에 종속되지 않는 오브젝트는 그만큼 깔끔한 코드가 될 수 있다.
  • POJO로 개발된 코드는 자동화된 테스트에 매우 유리하다.
    • 환경의 제약은 코드의 자동화된 테스트를 어렵게 한다.
  • 객체지향적인 설계를 자유롭게 적용할 수 있다.

3.5 POJO프레임워크

  • POJO 프로그래밍이 가능하도록 기술적인 기반을 제공하는 프레임워크를 POJO 프레임워크라고 한다. 스프링 프레임워크와 하이버네이트를 대표적인 POJO 프레임워크로 꼽을 수 있다.
  • 스프링을 이용하면 POJO 프로그래밍의 장점을 그대로 살려서 엔터프라이즈 애플리케이션의 핵심 로직을 객체지향적인 POJO를 기반으로 깔끔하게 구현하고, 동시에 엔터프라이즈 환경의 각종 서비스와 기술적인 필요를 POJO 방식으로 만들어진 코드에 적용할수있다.
  • 스프링은 비즈니스 로직의 복잡함과 엔터프라이즈 기술의 복잡함을 분리해서 구성할 수 있게 도와준다. 하지만 자신은 기술 영역에만 관여하지 비즈니스 로직을 담당하는 POJO에서는 모습을 감춘다. 데이터 액세스 로직이나 웹 UI 로직을 다룰 때만 최소한의 방법으로 관여한다. POJO 프레임워크로서 스프링은 자신을 직접 노출하지 않으면서 애플리케이션을 POJO로 쉽게 개발할 수 있게 지원해준다.

POJO프레임워크

스프링은 개발자들이 복잡한 엔터프라이즈 기술보다는 이러한 객체지향적인 설계와 개발의 원리에 좀 더 집중할 수 있도록 기회를 준다. 동시에 스프링이 제공하는 기술과, 프레임워크 API 및 확장 포인트는 그것을 이용하는 코드가 자연스럽게 객체지향적인 설계원리를 따라가도록 이끌어주기도 한다.

4. 스프링의 기술

  • 스프링에는 POJO 프로그래밍을 손쉽게 할 수 있도록 지원하는 세 가지 가능기술(enabling technology)을 제공한다.
  • IoC / DI
  • AOP
  • PSA
  • 스프링은 특정 기술을 지원해주는 단순한 프레임워크가 아니다. 스프링의 기술들은 스프링 프레임워크가 만들어진 진정한 목표인 POJO 기반의 엔터프라이즈 개발을 편리하게 해주는 도구일 뿐이다.

스프링은 엔터프라이즈 개발에 등장하는 다양한 기술에 대해 이미 잘 만들어진 서비스 추상화 기능을 제공하고 있지만, 그렇다고 스프링이 제공하는 PSA만 달랑 사용하고 말라는 뜻은 아니다. 스프링 사용자라면 스프링이 직접 제공하지 않는 기술에 대해서도 PSA를 적용할 줄 알아야 한다. 그것이 스프링의 목적과 개발 철학에 부합하는 스프링의 사용법이다. 그래서 스프링의 기술들은 스프링의 목적과 핵심 가치를 기준으로 살펴보고 이해하는 것이 중요하다.

4.1 IoC / DI

  • IoC/DI는 스프링의 가장 기본이 되는 기술이자 스프링의 핵심 개발 원칙이기도 하다. 나머지 두 가지 기술인 AOP와 PSA도 IoC/DI에 바탕을 두고 있다.
  • DI의 장점은 유연한 확장을 가능하게 해준다는 것이다. (OCP)

DI의 활용방법

  • 핵심기능의 변경 : DI의 가장 대표적인 적용 방법은 바로 의존대상의 구현을 바꾸는 것이다. 디자인 패턴의 전략 패턴이 대표적인 예다.
  • 핵심기능의 동적인 변경 : DI를 잘 활용하면 애플리케이션이 동작하는 중간에 그 의존 대상을 다이내믹하게 변경할 수 있다.
  • 부가기능의 추가 : DI의 세 번째 활용 방법은 핵심기능은 그대로 둔 채로 부가기능을 추가하는 것이다. 데코레이터 패턴을 생각해보면 된다. 부가 기능의 추가 방식을 특정 오브젝트가 아니라 좀 더 많은 대상으로 일반화해서 적용하면 AOP가 된다.
  • 인터페이스의 변경 : 클라이언트가 사용하는 인터페이스와 실제 오브젝트 사이에 인터페이스가 일치하지 않는 경우에도 DI가 유용하다. 이런 경우는 어댑터 오브젝트를 사용하면 된다. 인터페이스가 다른 오브젝트를 클라이언트가 사용하는 인터페이스로 바꿔주는 기능을 이용하면 되는 것이다
    • 좀 더 일반화해서 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 인터페이스 어댑터 역할을 해주는 레이어를 하나 추가하는 방법도 있다. DI의 응용 방법 중 하나이자 스프링의 대표적인 기술로도 분류되는 일관성 있는 서비스 추상화가 그런 방법이다.
  • 프록시 : 프록시 패턴의 구현은 DI를 통해 이루어진다.
  • 템플릿과 콜백 : 템플릿/콜백 패턴은 DI의 특별한 적용 방법이다. 반복적으로 등장하지만 항상 고정적인 작업 흐름과 그 사이에서 자주 바뀌는 부분을 분리해서 템플릿과 콜백으로 만들고 이를 DI 원리를 응용해 적용하면 지저분하게 매번 만들어야 하는 코드를 간결하게 만들 수 있다.
  • 싱글톤과 오브젝트 스코프 : DI가 필요한 중요한 이유 중 한 가지는 DI할 오브젝트의 생명주기를 제어할 수 있다는 것이다. DI를 프레임워크로 이용한다는 건 DI 대상 오브젝트를 컨테이너가 관리한다는 의미다. 오브젝트의 생성부터 관계설정, 이용 소멸에 이르기까지의 모든 과정을 DI 컨테이너가 주관하기 때문에 그 오브젝트의 스코프를 자유롭게 제어할 수 있다.
    • 가장 기본이 되는 스코프는 싱글톤이다.
  • 테스트 : 마지막으로 살펴볼 DI의 중요한 용도는 바로 테스트다. 여타 오브젝트와 협력해서 동작하는 오브젝트를 효과적으로 테스트하는 방법은 가능한 한 고립시키는 것이다. 즉 다른 오브젝트와의 사이에서 일어나는 일을 테스트를 위해 조작할 수 있도록 만든다. 그래야만 테스트 대상인 오브젝트의 기능에 충실하게 테스트가 가능하다.
    • DI를 위해 만든 수정자 메소드를 사용하면 테스트 코드 안에서 수동으로 목 오브젝트를 주입할 수 있다.

4.2 AOP

  • AOP는 객체지향 기술의 한계와 단점을 극복하도록 도와주는 보조적인 프로그래밍 기술이다. AOP를 사용하면 그 결과로 OOP를 더욱 OOP 답게 만들 수 있다.
  • 스프링의 목적인 POJO만으로 엔터프라이즈 애플리케이션을 개발하면서도 엔터프라이즈 서비스를 선언적으로 제공하는데 반드시 필요한 것이 바로 이 AOP 기술이다.
  • 스프링의 AOP는 스프링이 POJO 프로그래밍을 지원하려는 그 핵심 목적을 위해 중요한 역할을 하고 있다.

AOP 적용 기법

  • 첫 번째 : 스프링과 같이 다이내믹 프록시를 사용하는 방법이다
    • 부가기능을 부여할 수 있는 곳은 메소드의 호출이 일어나는 지점 뿐이라는 제약이 있다.
    • 스프링의 기본적인 AOP 구현 방법은 다이내믹 프록시를 이용하는 프록시 AOP 방식이다
  • 두 번째 : 자바 언어의 한계를 넘어서는 언어의 확장을 이용하는 방법이다
    • AspectJ라는 유명한 오픈소스 AOP 툴이 있다. 이 AspectJ는 강력한 고급 기능을 가진 AOP를 제공한다. AspectJ는 프록시 방식의 AOP에서는 불가능한 다양한 조인 포인트를 제공한다. 메소드 호출뿐 아니라 인스턴스 생성, 필드 액세스, 특정 호출 경로를 가진 메소드 호출 등에도 부가기능을 제공 할 수 있다.
    • 이런 고급 AOP 기능을 적용하려면 자바 언어와 JDK의 지원만으로는 불가능하다. 그 대신 별도의 AOP 컴파일러를 이용한 빌드 과정을 거치거나, 클래스가 메모리로 로딩될 때 그 바이트 코드를 조작하는 위빙과 같은 별도의 방법을 이용해야 한다.

AOP 적용 단계

AOP는 하나의 모듈이 수많은 오브젝트에 보이지 않게 적용되기 때문에 매우 주의해서 사용해야 한다.

  • AOP 적용 1단계: 미리 준비된 AOP 이용
    • 일단 처음에는 스프링이 미리 만들어서 제공하는 AOP 기능을 그대로 가져다 적용하는 것으로 시작한다.
  • AOP 적용 2단계: 전담팀을 통한 정책 AOP 적용
    • 애플리케이션 전체적으로 이용 가능한 것을 소수의 AOP 담당자 관리하에 적용
    • 보안, 로깅, 데이터 추적을 위한 트레이싱, 특정 구간의 실시간 성능 모니터링과 같은 정책적으로 적용할 만한 기능에 AOP를 이용해본다.
  • AOP 적용 3단계 : AOP의 자유로운 이용
    • 다른 팀이나 개발자가 만든 코드에 몰래 적용되는 AOP 기능은 만들어선 안 된다. 그런 위험만 주의한다면 얼마든지 개발자가 자신이 다루는 코드에 AOP를 적극 활용할 수 있다.

4.3 PSA

  • PSA는 환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근 할 수 있게 해준다.
  • POJO로 개발된 코드는 특정 환경이나 구현 방식에 종속적이지 않아야 한다. 스프링은 PSA를 통해 POJO에 특정 기술이나 환경과 관련된 코드가 들어가지 않도록 막아준다.
  • 스프링은 엔터프라이즈 개발에 사용되는 다양한 기술에 대한 서비스 추상화 기능을 제공한다. 어떤 것은 AOP나 템플릿/콜백 패턴과 결합돼서 사용되기 때문에 직접적으로 서비스를 이용 할 필요가 없다. 대신 설정을 통해 어떤 종류의 기술을 사용할 지 지정 해줘야 한다.
  • 스프링의 서비스 추상화의 개념과 장점을 잘 이해한다면 때에 따라 직접 서비스 추상화 기법을 적용할 필요도 있다.
  • 서비스 추상화는 단지 구체적인 기술에 종속되지 않게 하기 위해서만 사용되는 건 아니다. 테스트가 어렵게 만들어진 API나 설정을 통해 주요 기능을 외부에서 제어하게 만들고 싶을 때도 이용할 수 있다.

스프링이 어떻게 해서 엔터프라이즈 개발이 주는 복잡함을 제거하고, POJO 프로그래밍이라는 효과적인 방법을 사용할 수 있게 하는지에 관심을 갖는 것이 스프링을 가장 빠르게 이해하고 적용할 수 있는 지름길이다.