What is SpringFramework

: 엔터프라이즈급 자바 애플리케이션을 구축하기 위한 가벼운 프레임워크입니다.

스프링 프레임워크는 One-Stop-Shop으로 불릴 만큼 온갖 기능을 다 가지고 있습니다.

기능이 매우 많은데, 그중에서 필요한 부분만 가져다 쓸 수 있게 모듈화가 잘 되어 있습니다.

Spring의 특징

  • DI (Dependency Injection)
  • IoC (Inversion of Control)
  • AOP (Aspect Oriented Programming)
  • POJO (Plain Old Java Object)
  • 그 외의 특징
    • 모듈화가 잘되어 있습니다.
    • 선언적으로 트랜잭션을 관리할 수 있습니다.
    • 완전한 기능을 갖춘 MVC Framework를 제공합니다.
    • 스프링은 도메인 논리 코드와 쉽게 분리될 수 있는 구조로 되어있습니다.

IOC(Inversion of Control) / DI (Dependency Injection)

스프링 프레임워크는 IoC / DI 컨테이너입니다.

1) 컨테이너 (Container)

컨테이너는 인스턴스를 생성하고, 인스턴스를 총체적으로 관리합니다. 인스턴스의 생명주기를 관리하며, 인스턴스에게 추가 기능을 제공합니다. 예를 들어, 서블릿의 경우 실제로는 Servlet 컨테이너에서 동작하게 됩니다. 서블릿 클래스는 개발자가 작성하지만, 서블릿의 실행 및 관리를 담당하는 것은 서블릿 컨테이너인 것입니다. 스프링 프레임워크의 컨테이너를 스프링 컨테이너라고 부르고, 스프링 컨테이너에서 관리하는 인스턴스를 Bean이라고 부릅니다.

2) IoC (Inversion of Control)

img

프로그래밍에서는 개발자가 코드를 짜고, 짠대로 프로그램이 동작하는 것이 기본입니다.

즉, 프로그램 흐름 제어가 개발자에게 달려 있는 것입니다. IoC는 이러한 제어권이 역전되어,

컨테이너가 프로그램을 제어하게 되는 것을 말합니다.

이때, 컨테이너가 오브젝트의 제어권을 가지고 있어 원하는 대로 객체를 생성하고, 필요할 때만 개발자의 코드를 호출합니다. 예를 들어 원래 자바에서는 객체를 생성할때 new 연산자를 쓰는데, IoC가 일어나면 개발자가 new를 쓰는게 아니라 컨테이너에서 알아서 객체를 생성해서 개발자에게 주게 됩니다. GUI프로그래밍에서 쓰이는 이벤트 리스너가 비슷한 개념입니다.

3) DI (Dependency Injection)

img

DI는, 클래스 간의 의존 관계를 외부 설정 파일 등을 참고하여 자동으로 연결해주는 것을 말합니다.

의존관계에 대해 간단히 설명하자면, A클래스 내부에서 B클래스를 사용한다면 A클래스는 B클래스에 의존한다고 합니다. 이러한 의존 관계까 심화될수록 개발이 점점 어려워지게 됩니다. 스프링에서는 DI를 통해 의존 관계를 약화시킬수 있습니다.

****

1
2
3
4
5
6
7
8
9
class 보통엔진 {
}

class 터보엔진 {
}

class 자동차 {
     보통엔진 v5 = new 보통엔진();
}

자동차 클래스에서 보통엔진 객체를 직접 생성하고 있습니다. 만약 나중에 “보통엔진” 이 아니라 “터보엔진” 을 쓰고 싶다면, 자동차 클래스 내부의 코드를 변경하고 거기에다가 다시 컴파일까지 해야 됩니다. 아직 간단해서 실감이 안 날수 있지만, 클래스가 복잡해지면 이 과정이 매우 힘들어집니다. 자동차 클래스 내부의 코드를 바꾸지 않고도 “터보엔진” 을 쓸 방법이 없을까요?

<DI가 적용이 안 된 예시 2>

1
2
3
4
5
6
7
8
9
10
11
12
interface 엔진 {
}

class 보통엔진 implements 엔진 {
}

class 터보엔진 implements 엔진 {
}

class 자동차 {
     엔진 v5 = new 보통엔진();
}

고전적인 해결 방법인 인터페이스를 사용해서 좀 더 나은 코드를 만들어봤습니다. 인터페이스를 사용해 변수 v5의 자료형을 “엔진”으로 고정해서 쓸 수 있다는 것은 좋은데, 위에서 제시했던 문제점은 그대로입니다. 이 경우에도, “터보엔진” 으로 바꾸고 싶은 경우에는 자동차 클래스에서 객체를 생성하는 코드를 “엔진 v5 = new 터보엔진();” 으로 직접 수정하고 다시 컴파일까지 해야 됩니다. 인터페이스를 사용했지만, 인스턴스 타입을 바꾸기 위해 클래스를 수정해야 된다는 점은 변함이 없습니다.

****

1
2
3
4
5
6
7
8
9
10
11
12
interface 엔진 {
}

class 보통엔진 implements 엔진 {
}

class 터보엔진 implements 엔진 {
}

class 자동차 {
     엔진 v5;
}
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myengine" class="보통엔진"/>
	<bean id="car" class="자동차">
      <property name="v5" ref="myengine"/>
    </bean>

</beans>

스프링 프레임워크를 통해 DI를 적용했습니다. xml 파일이 하나 추가되었습니다. 이 xml은 스프링 컨테이너에서 Bean 관련 설정을 담당합니다. 지금 단계에서는 설정 파일의 문법을 모르셔도 됩니다. 중요한 것은 이렇게 만들면, 자동차 클래스 안에서 엔진 객체를 직접 생성하지 않는다는 것입니다. xml 설정을 보고 스프링 컨테이너가 자동으로 의존 관계에 맞게 객체를 생성해 주입해줍니다. 그리고 의존 관계가 주입된 객체는 스프링이 제공하는 메서드로 받아올 수 있습니다. 위의 xml을 의사 코드로 표현해보면 대략 다음과 같습니다.

1
2
3
보통엔진 myengine = new 보통엔진();
자동차 car = new 자동차();
car.v5 = myengine;

만약 나중에 “터보엔진” 을 쓰고 싶다면, 클래스 내부의 코드는 아무것도 바꿀 것이 없고, xml 설정에서 class를 “보통엔진” 에서 “터보엔진” 으로 바꾸기만 하면 됩니다. 아까 전까지는 클래스 내부의 코드를 수정해야 됐는데, DI가 이루어지니까 수정할 필요가 사라졌고 당연히 다시 컴파일 할 필요도 없습니다. 또한 클래스 코드를 수정하는 것보다는 xml 수정이 훨씬 간편합니다. 모두 스프링 프레임워크 덕분입니다.

AOP ( Aspect Oriented Programming )

관점 지향 프로그래밍이란?

어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화 하겠다는 것이다. 여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다.

예를 들어 핵심적인 관점은 결국 우리가 적용하고자 하는 핵심 비즈니스 로직이 된다. 또한 부가적인 관점은 핵심 로직을 실행하기 위해서 행해지는 데이터베이스 연결, 로깅, 파일 입출력 등을 예로 들 수 있다. AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 모듈화하겠다는 의미이다. 이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사(Crosscutting Concerns)라 부른다.

img

위와 같이 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지다.

  • AOP 주요 개념
    • Aspect : 위에서 설명한 흩어진 관심사를 모듈화 한 것. 주로 부가기능을 모듈화함.
    • Target : Aspect를 적용하는 곳 (클래스, 메서드..)
    • Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
    • JointPoint : Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용 가능
    • PointCut : JointPoint의 상세한 스펙을 정의한 것. ‘A란 메서드의 진입 시점에 호출할 것’과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음

POJO ( Plain Old Java Object)

: 스프링 애플리케이션 = POJO를 이용해서 만든 애플리케이션 로직 + POJO가 어떻게 관계를 맺고 동작하는지 정의해놓은 설계정보

POJO의 조건

  • 특정 규약에 종속되지 않는다.
    • 상속 받아서는 안된다.
  • 특정 환경에 종속되지 않는다.
    • 다른 환경에서 사용하기 어려움
    • 비즈니스 로직과 기술적인 내용을 담은 웹정보 코드가 섞여 이해하기 어려워짐
    • 웹서버에 올리지 않고 독립적으로 테스트하기 어려움
  • 단일 책임 원칙을 지키는 클래스
    • 책임과 역할이 각기 다른 코드를 하나의 클래스에 넣는 경우 진정한 POJO라 할 수 없다.

즉, POJO란 객체지향적인 원리에 충실하면서, 특정 환경과 규약에 종속되지 않아 필요에 따라 재사용될 수 있는 방식으로 설계된 오브젝트라 할 수 있다.

POJO의 장점

  • 특정 규약에 종속되지 않아 객체지향 설계를 할 수 있게 됨.
  • 특정 환경에 종속되지 않아 테스트 하기 좋음.
  • 특정 규약에 종속되지 않아 로우레벨 코드와 비즈니스 코드가 분리되어 깔끔한 코드 작성이 가능