부트캠프

Spring Framework 기본

hunm719 2023. 2. 3. 23:56

2.Spring Framework의 특징

2-1.POJO(Plain Old Java Object)
 -Java로 생성하는 순수한 객체

 -기본적인 규칙 2가지
  (1)Java나 Java의 스펙(사양)에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 함

Spring 삼각형


    -위의 예시는 과거 Struts라는 웹 프레임워크에서 지원하는 ActionForm클래스를 상속받는 경우로, 이렇게 특정 기술을 상속 해서 코드를 작성하게 되면 나중에 애플리케이션의 요구사항이 변경되서 다른 기술로 변경하려면 Struts의 클래스를 명시적으로 사용했던 부분을 전부 다 일일이 제거하거나 수정해야함
    -그리고, Java는 다중 상속을 지원하지 않기 때문에 ‘extends’ 키워드를 사용해서 한 번 상속을 하게되면 상위 클래스를 상속받아서 하위 클래스를 확장하는 객체지향 설계 기법을 적용하기 어려워짐

  (2)특정 환경에 종속적이지 않아야 함
   -순수 Java로 작성한 애플리케이션 코드내에서 Tomcat이 지원하는 API를 직접 가져다가 사용한다고 가정
    *서블릿(Servlet) 기반의 웹 애플리케이션을 실행 시키는 서블릿 컨테이너(Servlet Container)인 아파치 톰캣(Apache Tomcat)
   -만약 시스템의 요구 사항이 변경되어 Tomcat을 제외한 다른 Servlet Container를 사용하게 된다면?
   -애플리케이션 코드에서 사용하고 있는 Tomcat API 코드들을 모두 걷어내고 Zetty로 수정하거나, 최악의 경우에 애프리케이션을 전부 뜯어 고칠 수도 있음

  (3)POJO 프로그래밍이 필요한 이유
   -특정 환경이나 기술에 종속적이지 않으면 재사용 가능하고, 확장 가능한 유연한 코드를 작성 가능
   -특정 기술이나 환경에 종속적이지 않기 때문에 테스트가 단순해 짐
   -코드가 깔끔해지기 때문에 디버깅 용이
   -객체지향적인 설계를 제한없이 적용 가능(가장 중요한 이유)


2-2.POJO와 Spring Framework의 관계
 -Spring은 POJO 프로그래밍을 지향하는 Framework
 -최대한 다른 환경이나 기술에 종속적이지 않도록 하기 위한 POJO 프로그래밍 코드를 작성하기 위해서 Spring에서는 아래의 세가지 기술을 지원함
  (1)IoC(Inversion of Control)/DI(Dependency Injection)
  (2)AOP(Aspect Oriented Programming)
  (3)PSA(Portable Service Abstraction)

 +애플리케이션 프로그래밍 코드를 작성할 때 항상 내가 작성한 코드가 객체지향스러운가에 대한 고민을 하는 습관을 가지는 것이 중요


2-3.IoC/DI
 (1)IoC(Inversion of Control) : 제어의 역전, 애플리케이션 흐름의 주도권을 Spring이 갖는 것
  *Library는 애플리케이션 흐름의 주도권이 개발자에게 있고, Framework은 애플리케이션 흐름의 주도권이 Framework에 있음

  [1]일반적인 Java 콘솔 애플리케이션을 실행하려면 main() 메서드가 필요함

1
2
3
4
5
public class Example2_10 {
    public static void main(String[] args) {
        System.out.println("Hello IoC!");
    }
}
cs
  

  -위의 예시에서는 main() 메서드가 호출 된 다음 System 클래스를 통해서 static 멤버 변수인 out 의 println()을 호출함
  -위와 같이 개발자가 작성한 코드를 순차적으로 실행하는게 애플리케이션의 일반적인 제어 흐름
   *main() 메서드처럼 애플리케이션이 시작되는 지점을 엔트리 포인트(Entry point)라고 부름

  [2]Java 웹 애플리케이션에서 IoC가 적용되는 예

  -Java 콘솔 애플리케이션의 경우 main() 메서드가 종료되면 애플리케이션의 실행이 종료됨

서블릿 컨테이너의 서블릿 호출 예시


  -하지만 웹에서 동작하는 애플리케이션의 경우 클라이언트가 외부에서 접속해서 사용하는 서비스이기 때문에 main() 메서드가 종료되지 않아야 함
  -그런데 서블릿 컨테이너에는 서블릿 사양(Specification)에 맞게 작성된 서블릿 클래스만 존재하지 별도의 main() 메서드가 존재하지 않음
  -서블릿 컨테이너의 경우, 클라이언트의 요청이 들어올 때마다 서블릿 컨테이너 내의 컨테이너 로직(service() 메서드)이 서블릿을 직접 실행시킴(main() 메서드 필요x)
  -이 경우에는 서블릿 컨테이너가 서블릿을 제어하고 있기 때문에 흐름의 주도권이 서블릿 컨테이너에 있고, IoC(제어의 역전)의 개념이 적용되어 있는 경우

 (2)DI(Dependency Injection) : 의존성 주입
  [1]

클래스 간의 의존 관계를 나타내는 클래스 다이어그램 예시

  -위의 예시처럼 A 클래스가 B 클래스의 기능을 사용할 때, 'A클래스는 B클래스에 의존한다'라고 표현함

클래스 간의 의존 관계 예시 코드

  -위의 코드 예시에서 MenuController 클래스는 메뉴판에 표시되는 메뉴 목록을 조회하기 위해서 MenuService의 기능을 사용하고 있음
  -MenuController클래스는 클라이언트의 요청을 받는 엔드포인트(Endpoint : 클라이언트가 서버의 자원(리소스, Resource)을 이용하기 위한 끝 지점) 역할임
  -MenuService클래스는 MenuController클래스가 전달 받은 클라이언트의 요청을 처리하는 역할임
  -new 키워드를 사용해서 MenuService 클래스의 객체를 생성한 후, 이 객체로 MenuService의 getMenuList() 메서드를 호출하고 있음
   *이처럼 클래스 끼리는 사용하고자 하는 클래스의 객체를 생성해서 참조하게 되면 의존 관계가 성립함
   **두 클래스 간에 의존 관계는 성립 되었지만 아직까지 의존성 주입은 이루어지지 않음

의존성 주입 예시 코드

  -위의 코드 예시에서는 MenuController 생성자로 MenuService의 객체를 전달 받고 있음
  -이처럼 생성자를 통해서 어떤 클래스의 객체를 전달 받는 것을 '의존성 주입' 이라고 함
  -생성자의 파라미터로 객체를 전달하는 것을 '외부에서 객체를 주입한다'라고 표현하는 것
   *위의 코드 예시에서 객체를 주입해주는 외부는 CafeClient 클래스(MenuController의 생성자 파라미터로 menuService를 전달하고 있기 때문)

  [2]Tight Coupling 과 Loose Coupling
  -개발자가 DI를 사용할 때는 현재의 클래스 내부에서 외부 클래스의 객체를 생성하기 위한 new 키워드를 쓸지 말지 여부를 결정하는 것을 항상 염두에 두어야함
  -지금까지 객체를 생성할 때는 항상 new 키워드를 써왔지만, 애플리케이션 코드 내부에서 직접적으로 new 키워드를 사용할 경우 객체지향 설계의 관점에서 중요한 문제가 발생할 수 있음

MenuServiceStub으로 변경된 클래스

  -위의 코드 예시는 메뉴 데이터 조회 API를 위한 Stub을 요청받아 MenuServiceStub 클래스를 추가로 작성해서 코드 구성을 수정한 경우임
   *스텁(Stub)은 메서드가 호출되면 미리 준비된 데이터를 응답하는 것으로, 고정된 데이터이기 때문에 호출횟수와 관계없이 동일한 데이터를 리턴함(=멱등성(idempotent)을 가짐)
  -메뉴 목록 조회 API로 Stub을 제공하기 위해서 MenuServiceStub 클래스를 사용하는 것으로 변경(MenuServiceStub 클래스의 getMenuList()가 Stub데이터로 채워져있음)
  -하지만 MenuServiceStub 클래스를 사용하려고 보니, CafeClient와 MenuController에서 MenuService 를 MenuServiceStub 클래스로 불가피하게 변경해야함
   *결국 new 키워드를 사용해서 객체를 생성하게 되면 참조 할 클래스가 바뀌게 될 경우, 이 클래스를 사용하는 모든 클래스들을 수정할 수 밖에 없음

  -이처럼 new 키워드를 사용해서 의존 객체를 생성할 때, 클래스들 간에 강하게 결합(Tight Coupling)되어 있다고 표현함
  
  -Java에서 클래스들 간의 관계를 느슨하게 만드는 대표적인 방법은 인터페이스(Interface)를 사용하는 것

인터페이스를 사용한 클래스 간의 느슨한 결합 예시

  -위의 예시에 따르면 MenuController가 MenuService라는 클래스를 직접적으로 의존하는게 아니라 클래스 이름은 같지만 인터페이스를 의존하고 있음
  -MenuController 클래스 입장에서는 메뉴 목록 데이터를 조회할 수만 있으면 되기 때문에 MenuService의 구현체가 MenuServiceImpl이든 MenuServiceStub이든 상관 없음

인터페이스를 이용한 느슨한 결합 코드 예시

  -CafeClient 클래스의 (1)을 보면 new 로 MenuServiceStub 클래스의 객체를 생성해서 MenuService 인터페이스에 할당함
   *이처럼 인터페이스 타입의 변수에 해당 인터페이스의 구현 객체를 할당할 수 있는데 이를 업캐스팅(Upcasting)이라고 함
  
  [3]DI에서 Spring이 하는 일
  -Spring에서 지원하는 API코드를 통해 new 키워드로 생성하던 객체를 Spring이 대신하게 할 수 있음
  -하지만 POJO 프로그래밍 규칙 중 plain인 '다른 기술이나 규약에 얽매이지 않아야한다' 를 위반하기에 좋은 개발 방식이라고 하기 힘듦
  -그럼에도 Spring 코드(예시로 Config 클래스)로 new 키워드를 없앨 수 있기에 Config 클래스의 역할은 알고 넘어가야함
   *Config 클래스에 정의해둔 MenuController 객체를 Spring의 도움을 받아서 CafeClient클래스에게 제공을 하고 있는 것


 (3)AOP(Aspect Oriented Programming) : 관심 지향 프로그래밍
 -Aspect는 애플리케이션에 필요한 기능 중에서 공통적으로 적용되는 공통 기능에 대한 관심(공통 관심 사항 : Cross-cutting concern)과 관련됨
 -그리고 비즈니스 로직, 즉 애플리케이션의 주목적을 달성하기 위한 핵심 로직에 대한 관심사를 핵심 관심 사항(Core concern)이라고 표현함

애플리케이션의 공통 관심 사항과 핵심 관심 사항 예시

 -위의 이미지는 커피 주문을 위한 애플리케이션의 예시로, 가게 주인이 메뉴를 등록하고 고객이 커피를 주문하고 주문을 변경하는 기능은 애플리케이션의 핵심 관심 사항에 해당함
 -하지만 애플리케이션에 아무나 접속하지 못하도록 제한하는 애플리케이션 보안에 대한 부분은 애플리케이션 전반에 공통적으로 적용되는 기능이기 때문에 공통 관심 사항에 해당함
 
 -AOP는 애플리케이션의 핵심 업무 로직에서 로깅이나 보안, 트랜잭션 같은 공통 기능 로직들을 분리하는 것
  *애플리케이션의 핵심 업무 로직에서 공통 기능을 분리하는 이유
   [1]코드의 간결성 유지
   [2]객체 지향 설계 원칙에 맞는 코드 구현
   [3]코드의 재사용

 (4)PSA(Portable Service Abstraction) : 일관된 서비스 추상화
 -추상화(Abstraction)는 어떤 클래스의 본질적인 특성만을 추출해서 일반화 하는 것
 -Java에서 추상화를 표현할 수 있는 대표적인 방법이 추상 클래스와 인터페이스
 -PSA는 클라이언트가 추상화 된 상위 클래스를 일관되게 바라보며 하위 클래스의 기능을 사용하는 것
  *일반적으로 서버/클라이언트 측면에서는 서버 측 기능을 이용하는 쪽을 클라이언트라고 하듯이 코드 레벨에서 어떤 클래스의 기능을 사용하는 측 역시 클라이언트라고 부름

서비스 추상화 클래스 예시

 -위의 이미지에서 DbClient는 JdbcConnector 인터페이스를 통해 간접적으로 연결 되어(느슨한 결합) Connection 객체를 얻고 있음
 -이 때, DbClient에서 어떤 JdbcConnector 구현체를 사용하더라도 Connection을 얻는 방식은 getConnection() 메서드를 사용해야 하기 때문에 동일함(=일관된 방식)

 -이처럼 플리케이션에서 특정 서비스를 이용할 때, 서비스의 기능을 접근하는 방식 자체를 일관되게 유지하면서 기술 자체를 유연하게 사용할 수 있도록 하는 것을 PSA라고 함
  *PSA가 필요한 이유
   (1)애플리케이션에서 사용하는 기술이 변경되더라도 최소한의 변경만으로 변경된 요구 사항을 반영하기 위해서 = 애플리케이션의 요구 사항 변경에 유연하게 대처 가능



3.Spring Framework 모듈 구성

3-1.Architecture
 -아키텍처는 이해 당사자들을 위한 어떤 건물이나 구조물에 대한 컨셉을 잡는 것으로부터 시작
 -아키텍처의 범위는 너무 복잡하면 안 되고 기본적으로 최대한 심플함을 유지하기위해 노력

 -시스템 아키텍처는 하드웨어와 소프트웨어를 모두 포함하는 어떤 시스템의 전체적인 구성을 큰 그림으로 표현한 것
 -시스템 아키텍처를 통해 기본적으로 해당 시스템이 어떤 하드웨어로 구성되고, 어떤 소프트웨어를 사용하는지를 대략적으로 알 수 있음

 -웹 상에서 동작하는 웹 애플리케이션 아키텍처는 다양한 유형이 있지만 먼저 계층형 아키텍처(N-티어)를 간단히 살펴볼 예정

계층형 웹 애플리케이션 아키텍처

 -계층형 아키텍처
  (1)API 계층(API Layer) : 클라이언트의 요청을 받아들이는 계층
   *표현 계층(Presentation Layer)라고도 불리지만 REST API를 제공하는 애플리케이션의 경우 API 계층이라고 표현
  (2)서비스 계층(Service Layer) : 비즈니스 계층(Buisness Layer)라고도 불리며, API 계층에서 전달 받은 요청을 업무 도메인의 요구 사항에 맞게 비즈니스적으로 처리하는 계층
   *애플리케이션 개발에서 흔하게 사용하는 도메인이란 용어는 주로 비즈니스적인 어떤 업무 영역과 관련있음
  (3)데이터 액세스 계층(Data Access Layer) : 비즈니스 계층에서 처리된 데이터를 데이터베이스 등의 데이터 저장소에 저장하기 위한 계층


3-2.Architecture로 보는 Spring Framework 모듈(Module) 구성

Spring Framework 모듈 아키텍처

 -Java에서는 일반적으로, 지원되는 여러가지 기능들을 목적에 맞게 그룹화 하여 묶어 놓은 것을 모듈(Module)이라고 부름
 -일반적으로 모듈은 재사용 가능하도록 라이브러리 형태로 제공되는 경우가 많음
 -Spring Framework에서는 약 20여개의 모듈을 통해 다양한 기능들을 제공하고, AOP, Aspect, Servlet 같은 용어들 역시 아키텍처에서 확인할 수 있음



4.Spring Boot
 -Spring Boot은 Spring Framework의 편리함에도 불구하고 Spring 설정의 복잡함으로 인해 Spring 기반 애플리케이션 개발을 시작하기도 전에 어려움을 겪는 문제점을 해결하기 위해 생겨난 Spring Project 중 하나

 -Spring Boot를 사용해야 하는 이유
 (1)XML 기반의 복잡한 설계 방식 지양
  -Spring Boot 이전의 Spring 애플리케이션 개발을 위한 설정은 굉장히 복잡했으나 이제는 Spring Boot가 대신해줌
 (2)의존 라이브러리의 자동 관리
  -Spring Boot의 starter 모듈 구성 기능을 통해 의존 라이브러리를 수동으로 설정해야 하는 불편함이 사라짐
 (3)애플리케이션 설정의 자동 구성
  -Spring Boot은 스타터(Starter) 모듈을 통해 설치되는 의존 라이브러리를 기반으로 애플리케이션의 설정을 자동으로 구성함
 (4)프로덕션급 애플리케이션의 손쉬운 빌드
  -Spring Boot을 사용하면 직접 빌드 결과물을 War 파일 형태로 WAS(Web Application Server)에 올릴 필요가 없음
 (5)내장된 WAS를 통한 손쉬운 배포
  -Spring Boot은 Apache Tomcat이라는 WAS를 내장하고 있음

 *Spring Boot의 핵심 컨셉 : "Spring 구성은 Spring Boot에게 맡기고 비즈니스 로직에만 집중하자!"

 

 

 

 

-이미지 및 내용 출처 : code states

'부트캠프' 카테고리의 다른 글

Spring Framework 핵심 개념 - AOP  (1) 2023.02.09
Spring Framework 핵심 개념 - DI  (0) 2023.02.07
Spring Framework 소개  (1) 2023.02.02
관계형 데이터베이스 part2  (0) 2023.01.31
관계형 데이터베이스 part1  (0) 2023.01.30