포스트

스프링의 역사부터 기본 개념까지

아직 초짜라서 개념적으로 틀린부분이 있을 수 있으니 지적해주시면 정말 감사하겠습니다!

Spring의 등장 배경

Spring… 엔터프라이즈급 규모의 프로젝트에서 자주 채택되는 프레임워크이다.

본인도 첫 백엔드에 발을 담군것이 Spring이지만, Spring이 어떻게 등장했는지는 자세히 몰랐고 솔직히 큰 관심도 없었다…

그래서 스프링이 어떻게 등장하게 되었는지 나름대로 조사해보았다.

그전엔 EJB가 있었더라

스프링이 등장하기전, EJB (Enterprise JavaBeans)라는게 존재했었다.

EJB에 정확한 정의를 찾아보니

기업 환경에서 사용되는 대규모 분산 애플리케이션 개발을 위한 서버 측 컴포넌트 모델

이라고 한다

즉 기업환경이라 함은 엔터프라이즈 급이라는거고, 엔터프라이즈 급이라면 규모가 크고 복잡한 비즈니스 로직을 커버해줄수 있는 만큼의 성능(분산시스템, 보안, 디테일한 트랜잭션 제어기능 등등)을 가지고 있다는 의미로 생각된다.

EJB의 등장으로 개발자는 비즈니스 로직에 집중할수 있는 환경을 가지게 되었지만, EJB 컨테이너 라는, EJB를 어렵게 만든 주범떄문에 곤란함을 겪었다고 한다

EJB컨테이너는 우리가 흔히 사용하는 스프링 컨테이너로서의 개념과 크게 다르지않다. 컨테이너 기술이란 개발시 필요한 객체들을 관리하는 컨테이너를 만들어서 필요할 때마다 컨테이너로 부터 객체를 받는 기술이다.

만약 트래픽이 한번에 몰릴떄마다 객체를 생성한다면 서비스 부하와 트랜잭션 양이 많아서 처리에 오래걸릴 것이다.

EJB 컨테이너는 객체를 미리 생성해 풀(Pool)에 보관하고, 필요할 때마다 풀에서 객체를 가져와 사용하는 방식을 사용했다.

따라서 EJB컨테이너는 당시에는 획기적이라는 평가를 받았고, Java 진영에서 표준 기술로서 인정도 받았다고 한다

음? 그럼 EJB컨테이너는 좋은거 아님? 왜 이게 문제가 된거임??

그렇다. EJB컨테이너의 기능 자체는 무척 유용하다고 생각한다. 하지만 컨테이너를 사용하기까지의 설정이 너무 번거롭고 불편했다고 한다.

정확히는, EJB 2.X 버전 이하까지는 EJB를 사용하려면 deployment descriptor (DD)라는 XML 파일 작성해서 EJB 컴포넌트들을 일일히 설정했다.

이는 개발자가 비즈니스 로직 구현에 집중할 시간을 설정에 할애하게 만들었다.

즉, 비즈니스 로직에 집중하려고 EJB를 쓰는건데, 그 시간을 EJB컨테니어를 설정하는데 빼앗긴 것이다.

물론 익숙해진 시니어라면 금방 하겠지만, EJB를 처음 접하는 개발자에게는 큰 진입 장벽으로 작용했을 것 같다…

더 찾아보니, EJB의 단점으로 언급되는 문제들은 아래와 같다고 한다.

  • 높은 복잡성: EJB 컨테이너 자체의 복잡한 설정과 API, 배포 과정은 개발자에게 큰 부담으로 작용.

  • 무거운 기술: EJB는 대규모 분산 시스템을 위한 기술로 설계되어, 상대적으로 가벼운 애플리케이션 개발에는 과도하게 무겁고 복잡했슴.

  • 느린 개발 속도: EJB의 복잡성과 컨테이너 의존성은 개발 속도를 저해하는 요소로 작용했슴.

  • 특정 환경 및 기술에 종속적인 코드: EJB는 EJB 컨테이너와 Java EE 스펙에 종속적인 코드를 작성해야 했고 이는 이동성(Portabilty)이 부족하다는 평가를 받음

위 같은 문제 떄문에 복잡하지않고, 어디에도 종속되지 않는 객체로 돌아가자는 의미에서 마틴 파울러의 POJO(Plain Old Java Object)라는 용어가 등장하게 되었다.

그리고, EJB의 문제점을 해결하고자 그 유명한 Spring Framework가 등장하였다… 가볍고 유연한 아키텍처, POJO 기반 개발, 의존성 주입 등 혁신적인 기능을 제공하며 빠르게 인기를 얻었다고 한다.

이름의 유래를 찾아보니, 마침내 EJB라는 겨울이 가고 봄이 왔다는 의미에서 Spring이라고 지었다고 한다…

여기서 몰랐던건, 사실 스프링이 등장하고 나서 EJB 진영측에서도 위기감을 느껴 2006년에 EJB 3.0 버전을 발표했다.

Spring Framework의 영향을 받아 어노테이션 기반 설정, POJO 지원 등 개발 편의성을 크게 개선했다.

하지만 이미 Spring Framework가 대세로 자리 잡은 상황이었고, EJB의 초기 부정적인 인식을 완전히 뒤집기에는 역부족이였다고 한다..(첫 인상이 이래서 중요한가?)

Spring도 비슷하지만….SpringBoot가 있다면?

Spring Framework는 EJB의 단점을 많이 해결했지만, 여전히 일부 단점을 가지고 있다고 생각한다…

  • XML 설정: 초기 Spring Framework또한 XML 기반 설정이 주를 이루고 있고, 이는 설정 파일이 복잡해지고 관리가 어려워지는 문제를 야기할 수 있다.

  • 무거운 프레임워크: Spring Framework는 다양한 기능을 제공하는 만큼, 전체적으로 여전히 무거운 프레임워크이다.

  • 높은 학습 곡선: Spring Framework는 방대한 기능과 다양한 모듈을 제공하는 만큼, 동작 원리를 이해하고 활용하기 위해서는 상당한 학습 시간이 필요하다.

하지만 위 문제들은 Spring Boot를 활용하면 어느정도 해결이 가능하다.

스프링 부트는 Spring Framework 기반 애플리케이션을 쉽고 빠르게 개발할 수 있도록 도와주는 도구이다.

Spring Framework의 문제점들을 해결하고, 개발 생산성을 극대화하는 데 초점을 맞춘 Spring Framework의 확장판이라고 할 수 있다.

스프링 부트는 아래와 같은 기능을 제공해준다.

  • 자동 설정(Auto-configuration): 클래스패스에 있는 라이브러리와 설정 파일을 분석하여 자동으로 빈을 등록하고 설정을 적용하는 기능

    • @Configuration을 통해 자동으로 빈 설정 해줌(Bean이 뭔지 알고 싶다면?)
    • 개발자가 직접 설정 파일 (application.properties, application.yml)을 작성해서 실행 설정을 정의할 수 있다. Prod, local, test 등으로 환경을 나눌 수도 있음
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
      @Profile(value = {"prod"})
      @Configuration
      public class HttpConnectionProxyConfig {
      private static final String PROXY_HOST = "krmp-proxy.9rum.cc";
      private static final int PROXY_PORT = 3128;
      @Bean
      public RestTemplate restTemplateWithProxy() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
        requestFactory.setProxy(proxy);
        requestFactory.setConnectTimeout(5000);
        requestFactory.setReadTimeout(5000);
        return new RestTemplate(requestFactory);
      }
      }
      

      위 코드는 실제 프로젝트에서 사용한 HttpConnectionProxyConfig 코드이다.

프로파일이 “prod” 일때(즉, application-prod.yml 환경일때), RestTemplate라는 빈을 생성하고 객체로 등록한다.

프로파일이 다른 값일때는(prod, test, local 등등) 해당 빈은 등록되지 않는다.

  • Starter 의존성: 특정 기능을 위한 의존성들을 미리 정의해둔 “Starter”를 제공하여 의존성 관리를 간편하게 만든다. (보통 Spring Initializr로 초기설정을 한다)
    1
    2
    3
    4
    
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    
  • 내장 웹 서버: Tomcat, Jetty, Undertow 등의 웹 서버를 내장하고 있어 별도의 웹 서버 설치 없이 애플리케이션을 실행할 수 있다.

  • Actuator: 상태 확인, 메트릭 수집, HTTP 추적 등 운영에 필요한 기능을 제공하는 Actuator 모듈을 기본적으로 포함되어 있다.

스프링 부트와 관련된 내용을 여기서 다루기엔 방대하기도 하고 주제에서 벗어나므로, 추후에 조금식 풀어보도록 하겠다.

Spring 의 핵심 개념

이제 등장 배경을 알았으니, 스프링의 핵심개념들을 살펴 보도록 하자.

각 내용들을 깊이있게 이해하려면 실제로 활용하면서 부딪혀야 된다고 생각한다.

Core (DI, IoC)

스프링의 근간, 내가 만든 클래스를 스프링이 직접 관리하여 어플리케이션을 동작하게 한다

AOP(Aspect Oriented Programming)

공통적인 코드를 프레임워크 레벨에서 지원해주는 방법

Validation, Data binding

검증 그리고 외부에서 받은 데이터를 담아내는 방법

Resource

스프링 내부에서 설정이 들어있는 파일들에 접근하는 동작 원리

SpEL

짧은 표현식을 통해 필요한 데이터나 설정 값을 얻어올 수 있게 하는 특별한 형태의 표현식에 가까운 간편한 언어

Null-Safety

단어 그대로 null 에게서 안전한 프로그램 코드를 작성하는 기술을 제공

스프링의 디자인 철학

  • 모든 기능에서 다양한 가능성(다양한 모듈)을 사용 가능, 심지어 외부 모듈을 활용 가능
    • 너무 높은 자유도 어떤 점에서는 스프링을 어렵게 하는 요소
  • 유연하게 계속 추가 개발을 하고 있는 프레임워크

  • 이전 버전과의 강력한 호환성
    • 상당히 성숙하고 관리된 프레임워크이기 떄문에 레거시가 많음
    • 너무 많은 레거시 때문에 코드의 복잡성이 높아지긴 함
    • 따라서 스프링 내에는 동일한 역할을 하는 다양한 기능이 있으며, 그 중에서 적합한 방법을 선택할 수 있어야 함
  • API 디자인을 섬세하게 노력한다
    • 스프링 코드 자체가 하나의 좋은 참고 소스
  • 높은 코드 품질을 유지하려 함

→ 한마디로 높은 자유도를 주고 계속 발전하는 고품질의 다양성이 있는 프로젝트, 그런데 너무 자유로워서 때론 어렵다.(많은 레거시, 선택사항 존재)

다음 포스트는 위에서 언급한 핵심기술에 대해서 하나씩 설명해 보겠다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.