티스토리 뷰

Java & Spring

[Spring] 스프링 알아보기

강씨아저씨 2019. 1. 10. 20:51

이번 포스팅은 사내에서 Spring Framework 에 대해 공유하기 위해 Spring Framework 서적을 기반으로 학습하고 이해한 내용을 정리한 포스팅이다. 포스팅에서는 Spring 3 버전대의 내용 기준으로 설명할 예정이다. 

사실 전 회사에서 Spring Framework 를 사용했었고 현재 회사는 ruby on rails 를 사용하고 있기 때문에 Spring Framework 에 대해 깊이있게 다룰 생각은 없다. 다만 Spring Framework 가 지향하는 방향이나 핵심원리에 대해서 알고 있어야 다른 Framework 와의 차이점도 비교해볼 수 있고 시야를 넓힐 수 있기 때문에 이를 정리해 보려한다. 

스프링 프레임워크란?

우선은 Spring Framework 란 무엇일까 위키에서 검색해봤다. 위키에 설명된 내용을 보면
 "스프링 프레임워크(Spring Framework)는 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 간단히 스프링(Spring)이라고도 불린다. 동적인 웹 사이트를 개발하기 위한 여러 가지 서비스를 제공하고 있다. 대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자정부 표준프레임워크의 기반 기술로서 쓰이고 있다." 라고 한다. 쉽게 말하자면 "스프링 프레임워크는 자바를 이용하면서 웹 어플리케이션 서버를 만들때 주로 사용하는 프레임워크이고, 스프링이 대한민국에서 공공부문 정보시스템의 표준으로 사용되고 있다" 라고 생각하면 된다.
 그렇다면 스프링 프레임워크는 웹 어플리케이션 개발만을 위한 프레임워크 일까? 아니다. 내가 정의해본 스프링 프레임워크는 "엔터프라이즈 애플리케이션 개발시 비즈니스 로직에집중 할 수 있도록 도와주면서 비즈니스로직 외적인 부분들을 효율적으로 관리할 수 있게하는데 목적을 둔 프레임워크" 라고 생각한다.
 그리고 스프링은 스프링 프레임워크만 있는걸까? 역시 아니다. 스프링 프레임워크는 스프링 프로젝트들 중에 하나일뿐이고 스프링 배치나 스프링 안드로이드 등도 존재한다.( https://spring.io/projects ) 그리고 요즘은 자바뿐만 아니라 코틀린도 지원하고 있다고 한다. ( https://spring.io/guides/tutorials/spring-boot-kotlin/ )
 하지만 이하 내용에서는 스프링 프레임워크를 스프링이라 줄여서 표현하겠다 :)

스프링 기본원리

스프링은 기본적으로 비침투적인 방식을 지향한다. 여기서 비침투적인 방식이란 어딘가에서는 기술의 적용에 따라 필요한 작업을 해줘야 겠지만 기술의 적용 사실이 코드에 직접반영되지 않기때문에 어플리케이션 코드 여기저기에 기술에 필요한 흔적들이 불쑥 등장하지 않고 코드의 설계와 구현방식에 제한을 주지 않게 하기 위한 방식이다. 이렇게 비침투적인 방식을 지향하기때문에 개발자는 기술적용에 따른 설정들에 대해 덜 신경쓰고 비즈니스로직에 집중할 수 있게 된다.
 그리고 스프링에서는 지향하는 기본원리가 3가지 있다. 

앞으로 설명할 3가지 기본원리는 POJO( https://ko.wikipedia.org/wiki/Plain_Old_Java_Object ) 로 개발을 할 수 있게 하기위한 기술이라고 생각하면 된다.

IoC/DI ( Inversion of Control, 제어의역전 / Dependency Injection, 의존성 주입)

IoC/DI 는 스프링의 가장 기본이 되는 기술이자 스프링의 핵심 개발 원칙이기도 하다. 이후에 설명할 AOP와 PSA 도 IoC/DI 에 바탕을 두고 있다.
 IoC 는 제어의 역전으로 스프링에서 처음 등장한 개념은 아니고 상당히 오래전부터 있던 개념이다. 간단하게는 프로그램의 제어 흐름 구조를 뒤바뀌는 것이라고 이해하면 된다. 일반적으로는 main() 메소드와 같이 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고 , 결정한 오브젝트를 생성하고 만들어진 오브젝트에 잇는 메소드를 호출하고, 그 오브젝트 메소드 안에서 다음에 사용할 오브젝트를 결정하고 호출하는 식의 작업이 반복된다. 하지만 제어의 역전은 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않고 당연히 사용할 오브젝트를 생성하지도 않는다. 다음 예를 보자.

class A {
  public void NotUseIoc(){
    B b = new B();
    b.doMethod();
  }
}

 A 클래스가 B를 직접 호출하는게 일반적인 흐름의 방향이다. 이렇게 될 경우 A 클래스는 B 클래스를 사용한다는 것을 알고 있고 A클래스에서 B클래스를 생성해줘야 하기때문에 A클래스와 B클래스 사이에 강한 결합이 발생한다. 하지만 제어의 역전을 적용할경우 다음과 같은 방법으로 구현한다. 

class A {
  public void UseIoc(AbstractB b){
    b.doMethod();
  }
}

 외부에서 B 클래스를 주입받게 될 경우 A클래스는 B클래스를 생성해야 하는 책임을 갖을 필요가 없게 된다. 또한 B클래스를 직접 주입받지 않고 추상화된 계층을 하나 생성해서 인터페이스로 주입받게 될 경우 나중에 실제구현 클래스가 다른클래스로 교체되더라도 인터페이스만 지켜진다면 A 클래스의 변경이 생기지 않는다.  
 제어의 역전을 사용했을때도 어디선가는 A 클래스의 UseIoc 함수를 호출할때 B 클래스(혹은 인터페이스)를 매개변수로 넣어줘야 하는데 이렇게 클래스의 의존관계를 외부에서 관리하고 전달받는 방식을 의존성 주입(Dependency Injection, DI) 라고 한다. 
 제어의 역전 개념이 적용된 예를 찾아보면 디자인패턴중에서 탬플릿 메소드 패턴이 있고 프레임워크도 제어의 역전 개념이 적용된 기술이다. 라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접제어하지만 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 호출되고 사용된다.
 그렇다면 직접 자신이 사용할 오브젝트를 new 키워드로 생성해서 사용하는 강결합 방식보다 나은 점이 무엇일까? 이에 대한 가장 간단한 답변은 "유연한 확장이 가능하게 하기 위해서" 라고 할 수 있다.
 스프링에서는 IoC/DI 를 관리하기 위해 Application Context 라는 특별한 객체를 만들어서 사용한다. Application Context는 IoC/DI 대상들과 그들의 관계에 대해 알고 있고 필요한 시점에 각 대상들에게 필요한 정보들을 주입(DI)해주는 작업을 한다. 

PSA(Portable Service Abstraction, 서비스 추상화)

 서비스 추상화란 환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근할 수 있게 도와주는 방식이다. 엔터프라이즈 서비스를 개발하면서 추상화를 활용하면 실제 세부구현을 담당하는 모듈이 변경되더라도 상위 레이어에서는 모듈의변경을 의식할 필요없이 일관되게 형상을 유지할 수 있다.

 서비스 추상화에 필요한 기술은 DI를 활용하는 것으로 적극적으로 DI를 활용한다면 자연스럽게 서비스 추상화를 지키는 구조가 된다. 

AOP (aspect-oriented programming, 관점 지향 프로그래밍)

 관점지향 프로그래밍이라고 많이 알려진 AOP 도 스프링의 기본원리중 하나이다. AOP는 횡단관심사를 비즈니스 로직에서 분리하면서 메인 로직에 집중할 수 있도록 도와주는 방식으로 객체지향 프로그래밍(OOP) 처럼 독립적인 프로그래밍 패러다임이 아니라 객체지향 프로그래밍을 더욱 객체지향 스럽게 만들어 주기위해 도와주는 프로그래밍 기술이다. 

AOP가 적용된 사례를 보면 프록시 패턴을 이용한 로깅이나 트랜잭션 처리등을 예로들 수 있다. 

만약 일부함수들에 공통적으로 트랜잭션 처리를 해야한다면 위와같이 트랜잭션을 위한 코드들이 중복으로 생성되기 시작한다. 그리고 이렇게 생성된 코드들은 해당 클래스외에 DB에 사용되는 모든코드들에 공통적으로(횡단) 중복해서 생성된다. 이렇게 중복되는 로직은 클래스의 주요 관심사도 아니면서 모든 코드에 공통형상으로 관리해야 하는 문제가 있다. 
 이럴때 공통관심사(트랜잭션처리)를 주요 관심사에서 분리하기 위해 프록시 패턴을 이용하게 된다. 프록시 패턴을 이용하면 원래의 기능외에 추가적인 기능들을 부여할 수 있게되고 트랜잭션 처리는 프록시에게 위임하고 DAO 클래스는 본연의 기능에 맞게 데이터 접근에 집중 할 수 있게 된다. 

 그 후에 중복로직을 관리하기 위해 프록시 패턴을 개선한 다이나믹 프록시를 사용해서 중복로직들을 한곳으로 관리하게 한다. 스프링에서는 다이나믹 프록시의 단점들도 개선한 방식을 사용하게 된다. (물론 여기서 더 자세하게 다루진 않는다.)

이렇게 스프링에서 지향하는 3가지 기본원리에대해서 간략히 알아보았다. 스프링은 기본적으로 위의 3가지 기본원리를 지키고 있으며 스프링을 사용하지 않더라도 위의 3가지 원리에 대해서는 이해하고 있으면 많은 도움이 될 것 같다. 

오늘은 여기까지~

누군가에게 도움이 되었길 바라면서 오늘의 포스팅 끝~


댓글