7 분 소요

프레임 워크

- 애플리케이션을 개발하는데 필요한 구조와 구성을 제공
- 프레임워크만으로 애플리케이션이 동작하지는 않음

라이브러리

- 애플리케이션 개발에 필요한 내용을 미리 구현(작은 단위의 프로그램)하고 모아 놓은 것
- 필요할 때 호출하여 사용할 수 있다. 언제든지 재사용이 가능

어플리케이션의 흐름의 주도권(제어권)

- 프레임워크
	- 개발자가 아닌 프레임워크 스스로의 흐름(규약) 있음
	- 해당 규약에 맞추어 코드를 작성해야 함
- 라이브러리
	- 어플리케이션의 주도권(제어권)이 개발자에게 있음
	- 필요한 부분, 혹은 필요한 순간에 직접 개발자가 해당 라이브러리를 선택적으로 사용할 수 있음

프레임워크 장단점

- 장점
	- 정해진 규약이 있어 어플리케이션을 체계적으로 관리할 수 있따.
	- 기본적 설계와 필요한 라이브러리를 제공, 생산성 향상
	- 코드 재사용성이 높고 확장성이 좋다.
- 단점
	- 해당 프레임워크에 대한 학습이 필요(러닝커브 존재)
	- 자유롭고 유연한 개발 불가능

Spring 프레임워크

  • 기존의 자바 EE의 주요 기능을 보다 편리하고 모든 기능을 포함한 프레임워크로 개발의 효율을 높여준다는 점에서 차별점을 갖는다.
  • EE버전보다 높은 이용성으로 대부분의 EE 작업을 시장에서 대체하게 되었다.
  • DI와 트랜젝션 관리에 특화된 기능을 핵심으로 나온 자바 프레임워크이다.

스프링의 주요 기능

| 스프링 기능 | 설명 |
|:---|:---|
| `Core` | 다른 기능과 설정을 분리하기 위한 IoC 기능을 제공 |
| `Context` | 스프링 기본 기능으로서 어플리케이션의 각 기능을 하는 빈에 대한 접근 방법 제공 |
| `DAO` | JDBC 기능을 좀 더 편리하게 사용할 수 있도록 함 |
| `ORM` | 하이버네이트나 마이바티스 같은 영속성 관련 프레임워크와 연동된 기능 제공 |
| `AOP` | 관점 지향 기능 제공 |
| `Web` | 웹 어플리케이션 개발에 필요한 기능을 제공 |
| `WebMVC` | 스프링에서 MVC 구현에 관련된 기능을 제공 | ## 스프링 프레임워크의 주요 특징   1. POJO(Plain Old Java Object)   2. IoC(Inversion of Control)/DI(Dependency Injection)   3. AOP(Aspect Oriented Programming)   4. PSA(Portable Service Abstraction)

POJO(Plain Old Java Object)

	- 사전적 의미:단순한 자바 오브젝트
		- 객체 지향의 원리에 충실

	- 특정 규약(스펙이나 사양)에 종속되지 않는다.
		- 자바 언어외에 꼭 필요한 API 외에는 종속되지 않는다.
		- EJB Archtecture와 같이 규약에 따라 구현해야 하는 경우는 특정 클래스를 상속 받아야 한다.
			- 자바의 단일 상속제한으로 더이상 해당 클래스를 상속할 수 없음
			- 이는 곧 객체지향 설계가 어렵다는 의미
		- 만약 새로운 프레임워크를 프로세스에 적용한다고 할 때, 기존 프레임워크에서 사용하던 기능을 새로운 프레임워크에 맞게 바꿔야 하는데 그러면 새로운 프레임워크의 기술을 사용하고 기존 프레임워크의 기술로 작성된 내용은 다 지워야함.

	- 특정 환경에 종속되지 않는다.		
		- 특정 프레임워크에서만 동작하면 안된다.				
		- 웹 기반의 환경정보 혹은 웹 기술을 담고 있는 클래스 or 인터페이스를 사용하면 안된다.
			- 실제로 웹 컨트롤러와 연결되서 사용하더라도, 직접적으로 사용환경을 웹으로 제한하면 안된다.
			- HTTPServletRequest, HttpServletResponse 등
			- 예를 들어 WAS로 아파치 톰캣을 이용해 웹 서비스를 만들다가 Zetty라는 새로운 WAS로 바꾼다고 할 때, 기존 웹 서비스가 아파치 톰캣 API를 기반으로 만들어졌다면 이걸 처음부터 다 Zetty에 맞게 하나하나 소스코드를 뜯어고쳐야 한다.

	- 객체지향원리를 따라야 한다
		- 단순히 자바로 구현했다고 객체지향적 설계라고 보긴 어려움
		- 책임/역할이 분명히 나뉘어야 함
			- 하나의 클래스에는 하나의 책임, 역할만 존재해야 한다
			- 상속 다형성을 활용해야 한다
			- 조건문(if or switch)만을 활용하여 설계된 오브젝트는 POJO가 아니다.

	- 결국 POJO의 원칙(특정 규약, 특정 환경에 종속되지 않는다)을 준수함에 따라 우리는
		1. 저수준의 특정 기술들(특정 프레임워크, 특정 WAS에 기반한 기술들)을 쓰지 않아 코드가 좀 더 간결해짐
		2. 깔끔한 코드는 곧 쉬운 디버깅으로 이어짐
		3. 마찬가지 이유로 테스트하기도 쉬움
		4. 재사용이 쉬워지고 유연하게 코딩이 가능
		5. 무엇보다도 JAVA에 맞는 **객체지향적 설계**가 가능해진다(중요)
	- 스프링은 이 POJO라는 개념을 준수하는데 도움을 주고자 DI/IoC, AOP, PSA라는 3가지 개념을 소스코드에 적용시키도록 기술을 지원하는 역할을 한다.

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

	- 객체의 의존성을 역전시켜 객체간의 결합도를 줄이고, 유연한 코드를 작성할 수 있다.(낮은 결합도)
	- 가독성과 유지보수의 효율이 좋아지며 코드의 중복을 줄일  수 있다. #### DI의 개념을 이해하자

</img>

      private B1 b = new B1();
      b.getDate();
//      ↓↓↓↓↓↓↓↓↓↓↓
      private B2 b = new B2();
      b.getData();

위 코드에서 보듯이 B1 객체를 B2객체로 바꾸려면 해당 소스코드를 일일이 변경해야 하는데 위 예시와 달리 현실에서는 수천, 수만줄의 코드를 직접 수정해야하는 불상사가 발생한다. 이러한 소위 노가다 작업을 회피하기 위해서 스프링에서는 DI(Dependency Injection) 개념을 적용한 구조로 코드를 작성한다.

이를 위해선 변경할 부분(B1 -> B2)의 객체를 생성할 때, 타입을 B1,B2를 모두 다룰 수 있는, 즉 이들이 상속받은 인터페이스 타입으로 선언한다.

     private B b = new B2();
     b.getData();

하지만 이것으로는 부족하다 B1을 B2로 바꿔 타이핑한다는 점에서는 여전히 소스코드를 직접 수정해야한다는 한계가 있기 때문이다. 그렇다면 객체 타입을 인터페이스로 선언한 것처럼 “new B2()” 부분 역시 B1, B2 ….Bn까지의 모든 B를 대신할 수 있는 어떠한 것으로 바꾸어 주어야 한 것이다.

이를 위해서 객체 생성 코드(“new B2()”)를 외부에서 설정하도록 만들어 소스코드를 그래도 둘 수 있는 방법을 도입한다. 기존 자바에서는 이를 XML이나 Annotation 설정을 통해서 해결한다. (이에 대한 자세한 내용을 뉴렉처 강의 참고할 것)

스프링에서 사용하는 DI방식 역시 이와 유사한 구조로 진행된다.

  • 자바는 객체지향이기의 개념을 코드로 구현한 클래스, 객체들간의 관계로 이루어진다.
  • A와 B는 현실의 개념이며 이를 자바 코드로 구현하려한다. 이들은 서로 종속된 개념이다(예를 들어 자동차와 바퀴라고 가정하자)
  • 자동차 A는 바퀴 B를 일부분으로 가지고 있기에 이를 코드로 구현할 때 자신의 멤버 변수로서 구현한다.
  • 이때 이것을 어떤 코드구조로 하는지에 따라 방법이 나뉜다.
      class A{
    private B b;
    public A(){
      b = new B();
    }
      }
    
      class A{
    private B b;
    public A(){
    }
    public void setB(B b){
      this.b=b;
    
    }
    }
    
  • 전자의 경우 부품 B를 A가 인스턴화 됨과 동시에 B가 함께 생성되는 일체형이며
  • 후자의 경우 외부에서 객체 B를 A가 인스턴스화 된 이후에 setB()의 파라미터로 전달하여 A의 부분으로 만든다.
  • 후자가 전자보다 우수한 점은 B라는 A의 일부를 쉽게 다른 C, D, E로 쉽게 바꿀 수 있다는 것이다.
  • 전자는 A a = new A();로 선언 후 B를 다른 부품으로 바꾸기가 어렵지만
  • 후자의 경우 B b = new B(); A a = new A(); a.setB(b);의 방식으로 코드가 구성되어 B대신 얼마든지 B 자료형의 객체(C,D,~)로 바꿀 수 있는 것이다.
  • B b = new B();가 Dependency의 개념이라면 a.setB(b);는 Injection의 개념으로 이해할 수 있다.
  • 여기서 Injection을 구현할 때 a.setB(b)처럼 외부의 객체 b를 setter로 설정할 수도 있지만(Setter Injection) A a = new A(b);처럼 생성자의 파라미터로 전달할 수도 있다.(Construction Injection)

IoC(Inversion of Control)의 개념을 이해하자

  • 제어의 역전으로 번역되나 단어만 가지고는 도대체 무슨 말인지 이해되지 않는다.
  • 하나의 프로그램은 여러 객체들을 잘 조립하고 이어 완성된다.
  • 어떻게 객체들을 연결하고 구조를 짤 것인지가 프로그램에서 매우 중요한 과정이다.
  • 이걸 어떻게 할지 명시하는 방법은 XML파일을 이용하거나 Annotation을 이용하는 방법이 있다.

단순하게 프로그램으로 만들기 위한 여러 부품(여러 클래스와 객체들)들을 하나의 담아 관리할 필요가 있다. 이러한 부품, 부분들을 한데 모아 관리하는 가상의 장소를 우리는 컨테이너라고 한다.

이때 우리가 만들 프로그램의 부품들이 담겨있는 컨테이너를 IoC 컨테이너하고 한다. (요새는 DI 컨테이너라고도 하고 어샘블러, 오브젝트 팩토리 등의 이름으로 불리기도 한다)

  • 여기서 굳이 컨테이터에 IoC라고 붙이는 이유는 다음과 같다.
    • A⊃B⊃C⊃D라는 객체들이 서로 연결되어 있을 때(즉 상호간에 의존성이 있을 때)를 가정하자
    • DI를 설명할 때 예시에서 의존성 주입시 전자 일체형 방식(생성자에 매개변수넣어 생성과 후자 결합형 방식(SETTER()를 통한 방식)이 있었다.
    • 전자로는 A가 인스턴화 되면 생성자에 의해 차례로 B, C, D가 만들어 진다. - A가 멤버로 B라는 객체를 가지고, B는 멤버로 C 객체를 가지고 C는 D객체를 가진다.
    • 하지만 후자는 가장 작은 단위인 D를 먼저 만들고 C만들고 D를 C에 넣는 과정이 A까지 진행된다. - D가 있어야 C에 C setter의 매개변수로 넣을 수 있고 C 객체가 있어야 B의 setter로 C객체를 B의 멤버로 넣을 수 있기 때문
    • 최소 단위 부분부터 생성, 결합되어 결국 하나의 프로그램(혹은 이에 가까운) A가 만들어지는 것
    • 즉 후자는 전자처럼 A->D가 아닌 D->A 순서로 진행되므로 이를 IoC(Inversion of Control)이라고 부르는 것이다
    • 그리고 이 과정이 진행되는 가상의 장소가 바로 IoC 컨테이너인 것이다.
    • 간혹 IoC설명 중에 어플의 흐름이 개발자에 의해 관리되지 않고 컨테이너가 관리한다라는 내용이 있는데 위의 내용을 말하는 것이다

따라서 IoC란 개발자가 작성한 코드의 프로세스를 개발자가 하나하나 통제하다가도 특정 부분(A를 위해 B,C,D를 만드는 과정)은 프레임워크(스프링)이 작성된 코드를 대신 관리하여 프로세스를 이어받는 것을 의미한다. 프로세스의 주도권이 개발자에서 프레임워크로 넘어갔기 때문. - 여기서 만약 프레임워크 없이 개발자가 모든 코드를 다 통제, 관리한다면 이는 라이브러리를 이용한 것.(라이브러리가 뭘 대신 실행해주고 하는 것이 아니라 라이브러리를 개발자가 가져다가 필요에 맞게 사용하는 것이기에 주도권은 개발자에게 있는 것) 그리고 이 IoC란 추상적인 개념을 실제 코드로 구현하여 보여주는 것이 DI방식이다. 풀어서 설명하자 의존관계 주입의 절차를 개발자가 일일이 코드를 작성해 진행하는 것이 아니라 IoC 컨테이너(DI, 어샘블러 등등)가 대신 해준다는 것이다.

DI를 통한 IoC 컨테이너 생성

</img>

- 앞에서 DI와 Ioc가 무엇인지에 대해 설명 했는데 이것을 실제로 소스코드로 구현하는 방법은 여러 방법이 있다.
- 처음에는 소스코드에 직접 DI를 구현하는 작업은 스프링 이전에는 직접 하나하나 코드작성을 하여 이루어졌다.


위 예시 코드는 직접 소스코드로 작성한 DI의 예시이다. InlineExamConsole 객체는 Exam 타입의 exam 객체를 내부 멤버로 가지고 있기에 Exam 객체 examrhk-  InlineExamConsole객체(new InlineExamConsole)간에는 의존성이 존재한다 할 수 있다. InlineExamConsole 생성자의 매개변수로 exam를 넣어줌으로서 의존성이 주입된다.
이때 만약 기존에 사용하던 InlineExamConsole이라는 부품을 newExamConsole이라는 부품으로 변경하고자 하고자 한다면 newExamConsole 객체의 생성자의 매개변수로 exam을 넣어 새로운 의존성을 주입할 수 있다.
- 하지만 이 방법은 앞서 설명했던 것처럼 소스코드를 새로 써야하기에 번거롭고 부담이 큰 방법이다. 사람이 직접 코드를 쳐야하는 자칫 오타가 날 수도 있다
- *이러한 원시적인 방법을 개선하여 나타난 것이 SPRING의 DI 방식인 XML 파일을 이용한 방법이다.*
- 또 XML의 한계를 극복한 방법인 Annotation을 통한 SPRING DI가 만들어졌고 현재는 이 방법이 주류가 되었다.
- 이에 대한 자세한 설명은 따로 작성하도록 하겠다.(Spring XML 사용법 정리.md)

AOP(Aspect Oriented Programming)

	- 관심분리(Seperation of Concers)
		- 핵심 관심 사항, 횡단 관심(공통 관심) 사항
		- 높은 응집도를 가질 수 있다.(하나의 책임 SRP)

PSA(Portable Service Abstraction)

	- 환경의 변화에 상관 없이 일관된 방식(환경)으로 제공하는 추상화 구조
		- 인터페이스에서 추상 메서드를 만들 듯, 추상화된 서비스를 통해 환경이 바뀌어도 활용할 수 있어야 한다.
		- DI를 활용해 사용할 객체만 바꿔주도록 구현

카테고리:

업데이트:

댓글남기기