Spring Core/01. Overview

01. Spring Framework

  • -
반응형

이번 포스트에서는 SpringFramework의 기본적인 특징에 대해 살펴보자.

 

스프링이란?

 

Framework

스프링이란 자바 애플리케이션 개발을 위한 프레임워크이다.

여기서 프레임워크라는 멋진 용어가 등장하는데 프레임워크란 사전적으로는 뼈대 혹은 틀을 의미하며 프로그래밍에서는 비지니스 로직이 빠진 반제품 상태의 애플리케이션 정도로 해석된다.

프로그램이 아니더라도 우리는 일상생활에서 많은 프레임워크를 접한다.

예를 들어 아주 좋은 발표 주제가 생각났고 이를 발표하기 위한 자료를 만든다고 생각해보자. 전체적인 문서의 구조도 잡아야 하고 효율적으로 내용을 전달하기 위해 여러가지 복잡한 기능들이 떠오를 것이다. 이때 우리는 습관적으로 파워포인트를 찾는다.

발표 자료를 만들때는 대부분 PowerPoint를 쓰던데?

우리는 왜 파워포인트를 찾을까요? 파워포인트가 없다고 해서 발표자료를 못만들까?

그건 아니다. 조금 힘들고 어설프긴 하지만 메모장이나 그림판으로도 발표자료를 만들 수 있다. 다만 좀 더 편리하고 쉽게 생산성을 높이기 위해 파워포인트를 사용하는 것다.

그럼 파워포인트를 설치만 하면 알아서 발표 자료가 뚝딱 만들어질까? 역시 아니다. 파워포인트는 자체로 이미 훌륭한 제품이지만 이것 자체가 발표 자료는 아니다. 파워포인트에 컨텐트가 더해져야 비로서 멋진 발표자료가 생성되는 것이다.

 즉 파워포인트라는 반제품은 발표자가 편리하게 생각을 표현할 수 있는 도구인 것처럼
     프레임워크라는 반제품은 개발자가 편리하게 비지니스 로직을 구현할 수 있는 도구이다.

  컨텐트 프레임워크 결과물
발표 아이디어 파워포인트 발표 자료
프로그래밍 비지니스 로직 스프링 스프링 애플리케이션

 

Spring Framework

스프링 없이도 많은 시간과 인력이 있다면 충분히 프로젝트를 끝낼 수 있지만 스프링이 있다면 보다 짧은 시간에 적은 노력으로 우리가 이루려는 바를 달성할 수 가 있을 것이다.

 

아이디어=비지니스 로직, 파워포인트=스프링, 발표자료=애플리케이션

 

귀찮고 어려운 코드들일랑 스프링이 처리하라고 하로 개발자는 비지니스 로직에만 신경쓰면 된다. 예를 들어 JDBC 기반의 작업을 한다고 할 때 스프링을 적용 했을 때와 적용하지 않았을 때 개발자의 업무는 하늘과 땅 차이다.

개발자는 보다 비지니스 로직에 집중할 수 있게 되었다!

스프링을 몰랐을 때는 구현해야하는 비지니스 로직 이외에도 리소스 관리부터 예외 처리까지 신경써야 할 부분이 정말 많다. 하지만 Spring Framework를 사용하면 관련 동작은  스프링에서 설정에 따라 자동/반자동으로 처리하기 때문에 개발자는 비지니스 로직에만 신경 쓰면 된다.

 

Framework VS Library

언젠가 Framework와 Library의 차이점에 대한 질문이 모 기업의 면접에 나온적이 있다. 관련 글들이 인터넷에 많으니 한번쯤 정리하고 가기를 권장한다.

 

한줄 요약을 하면 누가 코드의 주도권을 가지고 있느냐에 차이점이 있다. 개발자는 라이브러리를 사용해서 비지니스 로직을 작성한다. 프레임워크는 개발자의 코드(비지니스 로직)을 호출해서 사용한다. 물론 이 과정에서 라이브러리를 사용하기도 한다. 따라서 개발자는 프레임워크가 원하는 형태로 코드를 작성해야 한다.

캡슐 커피 머신과 전열기구, 캡슐을 생각해보면?

 

개인적인 Framework 공략 방법

이처럼 Framework를 도입하면 개발자의 삶에도 칼퇴와 워라벨의 시대가 올것 같지만 막상 스프링을 공부해보면 무척 어려워서 차라리 이전 방식이 편하다는 친구들도 가끔 있다.(물론 틀렸다!) 

개인적으로는 이런 불상사가 프레임워크를 공부하는 방법을 잘못 선택했기 때문이라고 생각한다. 

우리는 파워포인트를 사용하면서 파워포인트의 원리에 대해 그다지 궁금해 하지 않는다. 파워포인트의 기능을 어떻게 사용하는지가 궁금하다. 이는 프레임워크를 바라보는 자세라고 할 수도 있는데 프레임워크에 대해서 우리가 공부할 것은 사용법이지 원리가 아니다. 물론 원리를 알면 당연히 더 좋겠지만 너무나 방대한 프레임워크의 원리를 모조리 이해하겠다고 파고 들다보면 그것을 이해하는 시점 정도에 프로젝트는 종료되어있을지도 모른다.

 

따라서 초급자의 경우는 메뉴얼을 보고 전자제품의 필요한 사용법을 익히듯 프레임워크의 기능을 어떻게 사용하는지 익히고 좀 숙련도가 올라가면 원리를 탐구하는 것이 좋은 방법이라고 생각한다.

 

스프링 부트

 

스프링 부트?

그럼 스프링 부트는 또 무엇인가? 스프링은 발표된 후 자바 엔터프라이즈 애플리케이션에서는 누구도 부정하지 못할 표준 아닌 표준이 되었다.  하지만 이런 스프링에게도 고민이 있었으니 바로 설정이 반이라는 점이다.

너무나 번거롭고 복잡한 설정은 스프링에 익숙해지는데 높은 장벽을 이 돼서 개발자들이 힘들었는데 이를 개선해서 설정 자동화를 이루어 내니 이것이 바로 스프링 부트이다.

스프링 부트와 상대적인 개념으로 이전까지의 스프링을 레거시 스프링(Legacy Spring)이라고 한다.

 

스프링 부트는 설정 자동화/간소화를 통해 개발 속도를 향상시키고 톰켓과 같은 WAS 환경을 내장해서 실행 속도도 개선했다. 또한 단위테스트를 강화해서 프로젝트의 안정성을 강화했다.

이로써 개발자는 좀 더 비지니스 로직 개발에만 집중할 수 있는 환경이 이뤄진 것이다. 결국 스프링 부트는 설정이 자동화/간소화된  스프링개발 방법이라고 볼 수 있다. 속을 들여다 보면 그냥 스프링이다. 

 

설정의 자동화의 예

스프링에서 DB를 사용하기 위해 DataSource를 연결한다고 생각해보자. 일단 레거시 스프링이나 스프링부트 모두 어떤 DB를 사용할 것인지와 DB에 접속하기 위한 driver class name, server url, username, password에 대한 정보는 필요하다.

<!-- pom.xml -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.2.224</version>
    <scope>test</scope>
</dependency>
#properties 파일 일부
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:~/spring-board
spring.datasource.username=quietjun
spring.datasource.password=

여기에 레거시 스프링의 경우 추가로 pom.xml에 DataSource에 대한 설정이 추가로 필요하고 아래처럼 이 데이터 소스를 생성하는 과정이 필요하다.

@Bean
DataSource ds(@Value("${spring.datasource.driver-class-name}")String driverClassName, 
              @Value("${spring.datasource.url}")String url, 
              @Value("${spring.datasource.username}")String username, 
              @Value("${spring.datasource.password}")String password) {
    HikariDataSource ds = new HikariDataSource();
    ds.setDriverClassName(driverClassName);
    ds.setJdbcUrl(url);
    ds.setUsername(username);
    ds.setPassword(password);
    return ds;
}

어떤 개발자가 코드를 작성하더라도 동일한텐데 아무튼 해야한다.

하지만 스프링 부트에서는 DB에 대한 설정이 있다면 자동으로 위에 준하는 동작을 다 처리해준다. 개발자는 단지 선언만 하면 끝이다. 

이런 설정은 spring-boot-autoconfigure-xxx.jar에 설정되어있다. 버전에 따라 다를 수는 있지만 jar 파일 내부의 META-INF>spring 폴더 안의 org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일을 살펴보면 어떤 내용들이 자동 설정되는지 확인할 수 있다.

 

스프링의 주요 특징

 

그럼 스프링은 어떤 특징을 가지고 있을까? 통상 스프링의 특징을 소개할 때는 스프링 삼각형이라는 것을 많이 활용한다.

스프링 삼각형

 

DI: Dependency Injection

DI는 Dependency Injection 즉 의존성 주입을 이야기 한다. 의존성이란? 우리가 어떤 행동을 수행할 때 필요한 것 또는 사용하는 것들을 말한다.

예를 들어 [자동차 여행]을 상상해보자. 일단 우리에게 필요한 것은 당연히 자동차인데 내가 운전해야 하는 자동차가 바로 의존성이다. 이때 고려해야 할 중요한 문제는 이 자동차를 '어떻게 가질 것인가?'이다. 차를 내가 직접 만들어서(?) 탈 수도 있고 렌트해서 빌려 탈 수도 있다.

차가 필요한데 만들까? 아니면 렌트할까?

만약 의존성인 차를 직접 만든다면 어떻게 만들어야 할지도 막막하거니와 이것 저것 신경써야 할 것들이 너무 많을 것이다. 만약 사고가 나거나 고장나는 상황은 생각만 해도 끔찍하다. 운전하랴, 문제 상황에 대처하랴 신경 쓸 일이 많다.

하지만 만약 차를 랜트한다면 어떨까? 누군가 차를 만들었을 꺼고 그 차가 나에게 왔을 것이다. 만약 차가 사고나거나 고장나면 담당자에게 연락해서 조치를 받으면 된다. 운전자는 맘 편히 운전만 하면 된다.

이처럼 DI는 필요한 의존성을 직접 생성하거나 관리하지 않는다. 대신 외부에서 만들어진 것을 주입 받아서 사용한다. 이로인해 개발자는 좀더 중요한 일인 비지니스 로직 개발에 집중할 수 있게 된다.

 

AOP: Aspect Oriented Programming

AOP 즉 Aspect Oriented Programming은 관점 지향 프로그래밍이다. 관점 지향 프로그래밍은 관심사의 분리(Separation of Concerns)를 통해 코드의 모듈화하고 재사용성을 강화하는 프로그래밍 패러다임이다.

예를 들어 "운전해서 출장가기" 라는 업무를 생각해보자.

먼저 AOP가 없는 상태를 억지로 상상해보자.

유독 일어나기 힘든 어느 아침. 중요한 출장이라 늦으면 안되기 때문에 밤새 시계를 쳐다보느라 잠을 설치고 만다. 괭한 눈을 비비며 출장지까지의 경로를 지도에서 찾아 겨우 겨우 운전해서 출장지에 도착한다.

지나친 걱정은 노화의 지름길

위 케이스에서 출장길은 시간을 확인하는 기능(1)길을 찾는 기능(2) 그리고 운전해서 출장지에 도착하는 기능(3)으로 구성되어있다. 이 중에서 가장 중요한 (3)을 제외한 (1), (2)는 (3)과는 상관 없긴 하지만 (1), (2)가 없다면 출장지에 제대로 도착하지 못했을 것이다. 이때 (3)에 해당하는 것을 핵심 관심사(core concern)라고 하고 (1), (2)를 횡단 관심사(cross cutting concern)라고 한다.

재밋는 점은 핵심 관심사는 [운전해서 출장가기]에만 존재하지만 횡단 관심사는 여기 저기서 똑같이 반복된다는 점이다. 예를 들어 시간을 확인하는 기능은 [퇴근 준비] 때도, [시험 종료 시간 확인]에도 필요하다. 길을 찾는 기능은 [자동차 여행 가기]에도 사용되고 [출근하기], [퇴근하기]에도 사용된다.

이런 횡단 관심사를 모듈화해서 재사용하는 것이 AOP의 핵심이다. 시간을 확인하는 일을 모듈화 해서 "알람 시계"를 만들고 길을 찾는 기능을 모듈화 해서 "네비게이션"을 만들면 어떨까? 그럼 위 의 출장은 아래와 같이 바뀔 것이다.

유독 일어나기 힘든 어느 아침. 알람 시계의 알람에 문제없이 눈을 뜬다. 차에 몸을 싣고 네비게이션에 목적지를 검색하고 운전해서 목적지에 안전하게 도착한다.

관심사의 분리를 통한 모듈화

이렇게 AOP를 사용하면 모듈화를 통해 코드의 유지보수성을 향상 시키고 디버깅을 용이하게 하는 등의 이점이 발생한다.

 

PSA: Portable Service Abstraction

PSA는 어떤 기술들에 대해 공통적으로 사용할 수 있는 부분을 추상화된 레이어로 제공한다는 의미이다. 여기서 Portable(이동 가능한)은 특정 환경이나 플랫폼에 종속되지 않고 다양한 환경, 플랫폼에서 동일하게 사용될 수 있다는 의미이다. PSA를 사용하면 필요한 기술을 내부에 숨겨 단순화 할 수 있고 결과적으로 일관된 방식으로 여러 기술에 접근할 수 있게 도와준다.

일상생활에서도 이런 PSA는 많이 접할 수 있다. 예를 들어 자동차의 기어를 바꾸는 과정에 대해 생각해보자. 생각을 해보기로 했지만 딱히 생각나지 않는다. 대략 아주 복잡한 기계적인 동작이 있을것이라고 추측만 가능할 뿐이다.

하지만 우리는 기어 변경을 잘 한다. 그냥 단순히 원하는 기어를 선택하기만 하면 된다. 이것이 복잡한 기술은 내부적으로 숨겨서 단순화 해두었기 때문이다.  이렇게 기어 변경이 단순화 되면 자전거의 기어 변경은 물론 선박의 기어 변경도 어렵지 않게 할 수 있다. 그냥 일관된 방식으로 기어만 선택하면 끝이다. 각 장비별로 따로 고민할 필요가 없어진다.

기어 조작을 위해 자동차를 공부할 필요는 없다!

스프링에서의 예를 들면 스프링에서 트렌젝션 처리를 위해서는 @Transactional 애너테이션만 적용하면 끝이다. 사실 트렌젝션 처리를 위해서는 트렌젝션 시작, commit, rollback 등의 개념이 들어가야 하지만 그런 것들은 내부적으로 숨겨지고 단지 @Transactional을 선언만 하면 된다. 그리고 이 방식은 JDBC를 쓰건 JPA를 쓰건 일관되게 적용할 수 있다.

 

POJO: Plain Old Java Object

마지막으로 스프링 삼각형의 가운데 있는 POJO라는 것은 위에서 이야기 했던 DI, AOP, PSA 등 멋진 내용을 처리하기 위해서 그냥 이전에 해오던 방식대로 평범한 자바 객체를 만들어서 사용하면 된다는 이야기 이다. 

과거 EJB에서도 이런 기능들을 수행할 수 있었는데 그때는 특정 빈을 상속받는 등 매우 복잡한 과정이 있었고 스프링은 상대적으로 그런 일 없이 그냥 평소처럼 자바 객체를 만들면 된다라는 의미로 해석될 수 있다.

EJB가 얼마나 악명이 높았냐면 Spring의 이름이 결정될 때 'EJB의 겨울이 끝났다'라는 의미도 있다고 한다. https://spring.io/blog/2006/11/09/spring-framework-the-origins-of-a-project-and-a-name

 

무언가를 상속 받아야 하는게 뭐가 그리 문제일까? 아주 좋은 기능성 의복을 생각해보자. 입기만 하면 극저온/극고온의 환경에서도 견딜 수 있게 해주고 숨쉬기 위한 깨끗한 산소 공급, 원격지에 있는 친구와 통신을 위한 위성통신 기능,  외부 충격 방지를 위한 헬멧과 훼손에 견딜 수 있는 두께 등 다양한 기능을 장착해보자.  결국 우주복 정도 되려나?

햇볕에 탈 걱정은 없다

이제 이 옷을 extends 해서 입고 해수욕장에 가보자. 위의 기능들이 하나도 필요없는데 어쩔 수 없이 가지고 있어야 한다.  나는 그냥 자연인으로 있더라도 나를 포함(Container)하는 환경이 똑똑해서 날씨가 추워지면 알아서 따뜻하게 해주고 전화 하고 싶을 때 친구와 연결되면 좋지 않을까?

이처럼 아무 조건 없이 클래스가 만들어진다면 특정 기술, 환경에 종속될 필요가 없어진다. 주변에서 필요한 것들을 제공해주면 된다. 당연히 스프링 프레임워크가 그런 역할을 수행한다.

또한 자바에서는 단일 상속이기 때문에 하나의 상속을 강요받으면 더 이상 다른 클래스를 상속할 수 없어 확장성 측면에서의 문제점도 발생한다.

반응형

'Spring Core > 01. Overview' 카테고리의 다른 글

04. application 설정 파일 작성  (2) 2024.03.11
03. Quick Start  (0) 2023.11.21
02. 환경설정 및 기본 곁가지 점검  (0) 2020.06.15
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.