Spring 이란?
Spring이란 간단히 말하면 Java 기반의 웹 어플리케이션을 개발할 수 있는 오픈소스 프레임워크이다. 더욱 자세하게 용어를 풀어 설명하자면 다음과 같다.
오픈소스
: 용어에서 알 수 있듯이, 소스가 공개되어 있어 모든 사용자들이 원한다면 자유롭게 확인, 수정, 배포할 수 있는 소스
프레임 워크
: 소프트웨어 개발에서 프로그램을 만들기 위한 기본 뼈대 역할이라 생각하면 된다. 쉽게 말해, 프레임워크는 자동차의 프레임, 기본적으로 구성하고 있는 뼈대라고 생각하면 쉽다. (https://moolgogiheart.tistory.com/87)
Spring 특징
Spring의 주요 특징은 다음과 같다.
- IoC (Inversion of Control)
- DI (Dependency Injection)
- AOP (Aspect Object Programming)
- POJO (Plan Old Java Object)
- MVC 패턴
- 생명주기 관리
IoC (Inversiont of Control)
영어를 그대로 번역하자면 ‘제어의 역전’이다.
기존의 JAVA 코딩을 생각해보면, new 연산자, 인터페이스 호출 등과 같이 개발자가 직접 객체를 생성 및 소멸하며 제어를 해왔다. 이러한 제어를 개발자가 아닌, 스프링 컨테이너가 대신 해주는 것을 말한다. 즉, 제어권이 개발자가 아닌 IoC에게 있으며, IoC에서 개발자의 코드를 호출하여 생명 주기를 관리하는 것이다.
IoC는 2가지로 분류할 수 있다.
DL (Dependency Lookup)
- 저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 찾는 것이다.
DI (Dependency Injection)
-
- DI는 의존관계 주입이라고 하는데, 우선적으로 의존관계에 대해 간단히 알아보자.
‘A가 B를 의존한다’ → 의존 대상인 B가 변하게 되면, A에도 영향이 있다는 것이다. - 프로그램에서 구성 요소 간의 의존 관계가 소스 코드 같은 내부가 아닌, 외부의 설정 파일을 통해 정의되는 방식을 말한다. 좀 더 쉽게 말하면, 만약 클래스 A가 클래스 B를 의존할 때 A에서 B Object를 직접 생성하지 않고 외부에서 생성하여 넘겨주면 의존성을 주입했다고 한다.
- 의존성 주입의 방식
- 생성자 주입
- 수정자 주입
- 필드 주입
- DI는 의존관계 주입이라고 하는데, 우선적으로 의존관계에 대해 간단히 알아보자.
스프링에서는 생성자를 통한 주입 방식을 권장하는 이유는?
- 순환 참조 방지
개발 시, A가 B를 참조하고, B가 다시 A를 참조하는 잘못된 코드를 작성할 수 있다. 이렇게 되면 순환 참조된다.
만약 필드 주입이나, 수정자 주입을 사용하였다면 어떨까?
→ Bean이 생성이 된 후 참조하기에 오류 없이 구동이 된다. 그렇게 된다면 실제 해당 코드가 발생할 때 까지 오류를 찾을 수 없다. 큰 개발에서 이러한 문제가 발생한다면 치명적일 수 있다.
만약, 생성자 주입을 한다면 어떨까?
→ 생성자 주입을 통해 주입 받았다면, 어플리케이션 구동 시에 BeanCurrentlyInCreationException이 발생하게 된다. 실제 구동이 되기 전 오류를 체크할 수 있고, 또한 어디서 오류가 발생했는지 콘솔을 통해 확인할 수 있다.
- 불변성
생성자를 통해 의존성을 주입 받는다면 final로 선언할 수 있고, 해당 객체가 변할 일이 사라지게 된다. 또한 해당 객체가 null로 들어갈 걱정도 하지 않아도 된다.
만약 필드 주입이나, 수정자 주입을 사용했다면 어떨까?
→ 만약 수정자 주입이나 메소드 주입을 이용하게 된다면 다른 개발자가 착각하여 의존성을 수정할 수 있다. 이는 SOLID 원칙에서의 OCP, 개방-폐쇄의 원칙을 위반하게 된다. 그렇기에 생성자 주입을 통해 변경의 가능성을 열어주지 않고, 불변성을 보장하는 것이 더욱 바람직하다. - 테스트 용이
의존성 주입을 사용 하는 이유는?
- 코드 재사용을 높여 소스코드를 다양한 곳에서 사용할 수 있다.
- 객체간의 관심사를 분리하여 더욱 객체지향스럽게 바꿀 수 있다.
- 결합도를 낮출 수 있다.
- 여기서 결합도란, 클래스가 다른 클래스와 연관된 정도를 말하는데 만일 결합도가 높게되면 클래스의 변경 시, 더불어서 변경해줘야 하는 클래스들이 많아지게 되는 문제점이 있다.
- 객체의 유연성이 올라간다.
AOP (Aspect Object Programming)
AOP는 관점 지향 프로그래밍이라고 불리는데, 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화 하겠다는 것이다.
- 핵심적인 관점 : 개발자가 적용하고자 하는 핵심 비즈니스 로직
- 부가적인 관점 : 핵심 로직을 수행하기 위한 DB 연결, 로깅, 파일 입출력 등
- 모듈화 : 어떠한 공통된 로직이나 기능을 하나의 단위로 묶는 것
예를 들어, 만약 A, B, C 클래스에 모두 공통적으로 반복해서 쓰는 코드가 있다고 가정해보자.
: 이렇게 공통적으로 반복해서 사용하는 코드를 흩어진 관심사 (Crosscutting Concerns)라 부른다. 이 처럼 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리해서 재사용하는 것이 AOP이다.
AOP를 사용하는 이유는 무엇일까?
→ 공통의 기능을 한 곳에 모아 놓고 사용할 수 있기에 유지 보수 측면에서 용이하다. 또한 Service 모듈들이 각자의 역할에 충실하여 구현할 수 있기에 더욱 객체지향스럽다.
만일 AOP를 사용하지 않고 놔두면 어떨까?
→ 만약 A, B, C 클래스에서 공통으로 사용하는 코드의 수정이 필요할 경우, 모든 클래스에서 수정을 해줘야 한다. 이는 유지보수 측면에서 유용하지 못하다. 또한, 코드가 많아지게 되어 공통의 코드를 사용하는 다른 클래스에서 수정을 해주지 못할 가능성도 존재한다.
AOP 적용 방법
- 컴파일 타임
- 로드 타임
- 런타임
→ 스프링 AOP가 사용하는 방법
POJO (Plan Old Java Object)
POJO는 말 그대로 오래된 방식의 간단한 자바 오브젝트라는 의미로, Java EE 등의 중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 '무거운' 객체를 만들게 된 것에 반발해서 사용하게 된 용어이다.
현재 POJO는 주로 특정 자바 모델이나 기능, 프레임워크 등을 따르지 않은 자바 오브젝트를 지칭하는 말로 사용된다. 그 중 Spring Framwork는 POJO 방식의 프레임워크이다.
즉, 다시 말하면 POJO란 특정 기술에 종속되지 않는 순수한 자바 객체를 의미한다.
조금 더 자세하게 설명하자면,
EJB 등에서 사용되는 Java Bean이 아닌 Getter / Setter로 구성된 가장 순수한 형태의 기본 클래스를 POJO라 한다.
EJB (Enterprise Java Beans) ?
: EJB란 자바 개발에 있어 로우개발에 신경 쓰지 않고 어플리케이션을 쉽게 만들어 준 기술이다. 하지만, EJB는 객체지향성을 감소시키는 단점이 존재한다.
EJB의 사용과 프로그램의 규모 증가로 인해, 특정 기술과 환경에 종속되어 의존하게 된 자바 코드는 가독성이 떨어지고, 유지보수에 어려움이 생기게 된다. 또한 확작성이 떨어지고, 이로써 점차 객체지향성을 잃어갔다.
POJO의 조건은 무엇일까?
- 특정 규약에 종속되지 않는다.
: 자바 언어와 꼭 필요한 API외에는 종속되지 말아야한다. - 특정 환경에 종속되지 않는다.
: 특정 기업의 프레임워크나 서버에서만 동작가능한 코드라면, POJO라 할 수 없다. 즉, POJO는 환경에 독립적이여야한다. - 객체 지향적 원리에 충실해야 한다.
: POJO는 객체지향적인 자바언어의 기본에 충실하게 만들어져야한다.
MVC 패턴
MVC란 Model - View - Controller의 약자로, 애플리케이션을 세 가지 역할로 구분한 개발 방법론이다.
소프트웨어 디자인 패턴으로, 해당 MVC 패턴을 성공적으로 사용한다면 사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션의 시각적 요소나, 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있게 된다.
앞서 말한 내용에서의 핵심은 MVC 패턴을 사용하게 되면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 비즈니스 로직을 쉽게 고칠 수 있는 어플리케이션이 된다는 것이다.
Model, View, Controller 가 하는 역할은 무엇일까?
Model
데이터와 애플리케이션이 무엇을 할 것인지를 정의하는 부분으로, 내부 비즈니스 로직을 처리하기 위한 역할을 한다. 즉, 모델은 컨트롤러가 호출을 하면 DB와 연동하여 사용자의 입출력 데이터를 다루는 일과 같은 데이터와 연관된 비즈니스 로직을 처리하는 역할을 한다. 데이터 추출, 저장, 삭제, 업데이트 등의 역할을 수행한다.
또한 Model은 다음과 같은 규칙을 가진다.
- 사용자가 편집하기를 원하는 모든 데이터를 가지고 있어야 한다.
- View나 Controller에 대해 어떠한 정보도 알지 말아야 한다.
- 변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야 한다.
View
View는 사용자에게 보여주는 화면(UI)에 해당하는 부분이다. 사용자와 상호작용하며, Controller로부터 받은 Model의 결과 값을 사용자에게 화면으로 출력하는 일을 한다. 또한 다중의 View가 존재할 수 있고, Model에서 받은 데이터는 별도로 저장하지는 않는다.
View는 다음과 같은 규칙을 가진다.
- Model이 갖고 있는 정보를 저장해서는 안된다
- Model이나 Controller와 같이 다른 구성요소들을 몰라야 한다.
- 변경이 일어나면 변경 통지에 대한 처리방법을 구현해야 한다.
가장 중요한 것은 'Model과 View는 서로의 존재를 몰라야 한다'
Controller
Controller는 Model과 View 사이를 이어주는 인터페이스 역할을 한다. 즉, Model이 데이터를 어떻게 처리할지 알려주는 역할을 한다. 사용자로부터 View에 요청이 있으면 Controller는 해당 업무를 수행하는 Model을 호출하고, Model이 업무를 모두 수행하면 결과를 View에 전달하는 역할을 한다.
Controller는 다음과 같은 규칙을 가진다.
- Model이나 View에 대해서 알고 있어야 한다.
- Model이나 View의 변경을 모니터링 해야 한다.
MVC 패턴을 사용하는 이유는 ?
- 비즈니스 로직과, UI 로직을 분리하여 유지보수를 독립적으로 수행이 가능.
- Model과 View가 다른 컴포넌트들에 종속되지 않아서, 확작성과 유연성에 좋다.
- 중복 코딩의 문제점을 제거할 수 있다.