▶CodeStates Back-End/Section 2

TIL [0614] Spring Framework

휴학생감자 2022. 6. 14. 22:46

 

Framework

어플리케이션 간의 통신이나, 데이터 저장소에 저장하는 다양한 기능들을 라이브러리의 형태로 제공하여 개발자가 핵심 로직 개발에 집중할 수 있도록 돕는 것

 

Spring Framework

자바 기반의 웹 어플리케이션을 개발하는데 필요한 framework

 

 

# Framework vs. Library

라이브러리는 개발자가 코드를 짜면서 필요한 기능을 해당하는 라이브러리에서 호출해서 사용할 수 있도록 만들어놓은 것이다. 즉, 어플리케이션 흐름의 주도권이 개발자에게 있다.

반면, 개발자가 작성한 코드를 사용하여 어플리케이션의 흐름을 만들어내는 것을 framework이 해주므로, 어플리케이션 흐름의 주도권을 spring framework이 가진다.

 

 

♧ 스프링 이전의 기술들...

JSP(Java Server Page)

→ 클라이언트에게 보여지는 View 코드와 서버의 코드가 섞여있는 형태

Java Servlet

→ 클라이언트 웹 요청 처리에 특화된 자바 클래스의 일종으로 서블릿을 위한 자바코드가 클라이언트 코드에서 분리되어 별도로 관리되는 형태 (물론 JSP, Spring 모두 내부적으로는 서블릿을 사용한다!!)

Spring MVC 방식

→ 데이터를 꺼내오거나, character set 지정 등의 작업을 spring이 처리해주어 코드가 간결한 장점을 가지지만, 어플리케이션의 기본 구조를 잡는 설정 작업이 불편함.

 

결론...Spring Boot..

 

 


 

 

[ Spring Framework의 특징 ]

 

 

① POJO (Plain Old Java Object)

 

순수 자바 객체만을 사용해서 프로그래밍 코드를 작성하는 것

 

☆ 규칙1. 다른 기술이나 규약에 얾매이지 않기 (자바 or 자바 사양에 정의된 것 제외)

                   - 특정 기술을 상속한은 경우 요구사항 변경이 힘들다.

☆ 규칙2. 특정 환경에 종속적이지 않기

                   - 서블릿 컨테이너와 같은 API 변경이 불가능해질 수 있다.

 

# POJO 프로그래밍이 필요한 이유

   재사용이 가능하고, 확장 가능한 유연한 코드 작성이 가능하다.

   저수준의 기술과 환경 종속적 코드를 제거하여 깔끔해진다.

   디버깅이 쉬워지고, 테스트가 단순해진다.

   객체지향적인 설계를 제한없이 적용할 수 있다.

 

→ POJO 프로그래밍을 위한 세가지 기술 : Ioc/DI, AOP, PSA

 


 

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

 

어플리케이션 흐름의 주도권이 뒤바뀐 것을 IoC(제어의 역전)이며, 이를 구체화한 것이 DI(의존성 주입)

 

# 서블릿과 웹 어플리케이션 간의 IoC

일반적으로 Java console app을 통해 실행하면 main( ) 메서드가 실행되면서 코드가 순차적으로 실행되는 흐름을 가진다.

메인 메서드가 종료되면 어플리케이션의 실행 또한 종료된다.

(Entry Point : 어플리케이션의 시작 지점 >> main( ) )

(End Point : 클라이언트가 서버의 자원을 이용하기 위한 끝 지점)

 

그러나, 웹 상에서 돌아가는 Java web app의 경우 main( ) 메서드가 존재하지 않는다.

클라이언트의 요청이 들어올 때마다, 서블릿 컨테이너 내의 컨테이너 로직이 각 서블릿을 직접 실행시켜준다.

따라서 서블릿 컨테이너가 서블릿을 제어함으로써 어플리케이션의 주도권을 가지는 것으로 본다.

 

+) Servlet Container (서블릿 컨테이너)

서블릿 기반의 웹 어플리케이션의 실행부터 서블릿의 생명 주기 관리, 쓰레드 풀 생성을 통한 서블릿과 쓰레드 매핑 등을 담당

Ex. 아파치 톰캣

 

 

# 객체지향 프로그래밍에서의 DI

객체지향에서의 의존성은 대부분 객체 간의 의존성을 말한다.

만약 A클래스가 B클래스의 메서드를 호출한다면, 'A클래스가 B클래스에 의존한다'고 한다.

 

Ex) Banana banana = new Banana( );

        Fruit fruit = new Fruit(banana);

사용하고자 하는 클래스의 객체를 생성하여 참조하면 의존 관계가 성립하게 된다.

 

결국, 의존성 주입 = 외부에서 객체를 주입한다 = 생성자의 매개변수로 객체를 전달하다!!

 

 

# 의존성 주입의 필요성과 느슨한 결합

프로그래밍을 하면서 생성자를 통해 객체를 전달하는 일은 너무도 흔하므로 의존성 주입은 필요한 것이 아닌 당연한 것이다.

그러나 외부 클래스의 객체 생성을 위해 new 키워드를 사용하면 클래스 간의 강한 결합(Tight Coupling)이 생긴다.

따라서, 의존성 주입을 하더라도 클래스 간의 관계는 느슨해야 한다.

 

느슨한 의존성 주입은 '인터페이스'를 통해 구현한다.

어떤 클래스가 인터페이스와 같이 일반화된 구성 요소에 의존하면 클래스가 서로 느슨하게 결합된다.(Loose Coupling)

즉, 인터페이스를 구현한 어떠한 클래스던지 매개변수로 받을 수 있기 때문이다.

 

 

→ 스프링 기반의 어플리케이션에서는 의존성 주입을 spring API가 대신 해준다.

 


 

③ AOP (Aspect Oriented Programming)

 

어플리케이션의 핵심 업무 로직에서 공통 기능 로직들을 분리한 관심 지향 프로그래밍

 

# 어플리케이션에 필요한 기능들

공통 관심 사항(Cross-cutting concern) : 어플리케이션 전반에 걸쳐 공통적으로 사용되는 기능들에 대한 관심사

                                                                              Ex) 로깅, 보안, 트랜잭션 처리

핵심 관심 사항(Core concern) : 어플리케이션의 주목적을 달성하기 위한 핵심 로직에 대한 관심사 

                                                            Ex) 별다방 앱 - 메뉴 등록, 사이렌 오더, 제품 구매

 

 

# 핵심 로직에서 공통 기능을 분리하는 이유

코드는 복잡할수록 버그가 발생할 가능성도 높고, 유지 보수도 어려워진다.

AOP 방식을 이용하면 코드를 간결하게 만들 수 있고, 모듈별로 나누어 코드를 재사용하기 쉬워지므로

객체 지향 설계 원칙에 맞는 코드를 구현할 수 있다.

따라서, 어플리케이션 전반에 걸친 공통 기능과 같은 것은 비즈니스 로직에서 재사용 가능한 모듈로 사용 가능하다.

(중복된 코드의 공통화)

 

 

→ 스프링은 트랜잭션 처리 기능을 AOP를 통해 공통화 해놓았다. 이를 활용하면 어플리케이션의 공통 기능들을 비즈니스 로직에서 분리하여 재사용 가능한 모듈로 사용할 수 있다.

 


 

④ PSA (Portable Service Abstraction)

 

클라이언트가 추상화된 상위 클래스를 일관되게 바라보며, 하위 클래스의 기능을 사용하는 것

 

+) 클라이언트 : 일반적으로 서버의 기능을 이용하는 쪽을 말하며, 코드 레벨에서 특정 클래스의 기능을 사용하는 측도 클라이언트에 해당한다.

 

# 서비스에 적용한 PSA

요구사항의 변경에도 서비스 이용이 가능하도록 서비스의 기능에 접근하는 방식을 일관되게 유지하며, 기술 자체를 유연하게 사용할 수 있도록 한다.

 

Ex) 외부 클라이언트가 JdbcConnector를 사용하는 서비스

클라이언트는 데이터베이스 연결을 위해 JdbcConnector를 사용하려고 한다. JdbcConnector는 어플리케이션에서 이용하는 하나의 서비스이다. 클라이언트는 인터페이스를 통해 간접 연결(Loose tight)되어 객체를 얻는다. 따라서, 어떤 JdbcConnector 구현체를 사용하더라도 getConnection() 메서드를 사용하는 것은 동일하다.

즉, 일관된 방식으로 해당 서비스의 기능을 사용할 수 있다.

 

 

# PSA의 필요성

어플리케이션에서 사용하는 기술이 변경되거나 요구사항이 수정되더라도, 최소한의 코드 변경을 통해 요구 사항을 반영하고 이에 유연하게 대처하기 위함이다. 즉, 서비스의 기능에 접근하는 방식은 일관되게 유지하며, 기술 자체를 유연하게 사용할 수 있도록 프로그래밍해야 하는 것이다.

 

 

→ 스프링은 상황에 따라 기술이 바뀌더라도 변경된 기술에 일관된 방식으로 접근 가능하도록 지원한다.