dev-course day17

2rlokr·2025년 3월 26일

dev-course

목록 보기
17/43
post-thumbnail

오늘 배운 것

Spring Framework

자바를 개발하기 위한 프레임워크로서, 절대적이 위치를 차지하고 있다. Java 플랫폼에서의 엔터프라이즈 애플리케이션 개발을 위한 솔루션(Java EE)의 대체재를 제공하기 위해 시작되었다.

서브 프레임워크
Spring Data, Spring Security, Spring Batch, Spring Cloud, Spring AMQP 등 다양한 서브 프레임워크를 포함하고 있어, 개발자가 웹 애플리케이션을 효율적으로 개발할 수 있도록 도와준다.

Spring의 개발 철학
불필요한 것은 없애고, 필요한 것만 남기자!

Library 와 Framework

소프트웨어 개발할 때 도움을 주는 다른 사람들이 만든 소프트웨어

Library
프로그램의 흐름을 개발자가 직접 제어하는 소프트웨어

Framework

  • 프로그램의 전체적인 흐름과 구조는 소프트웨어가 가져가고, 개발자는 필요한 부분만 작성하게 되는 소프트웨어
    => 제어의 역전 (Inversion of Control)
  • 소프트웨어 개발에서 자주 사용되는 구조적 설계의 집합으로, 개발자가 애플리케이션을 구축할 때 기본적인 골격과 도구를 제공하여 개발 과정을 단순화하고 표준화하는 데 도움을 준다.

개념

Spring Framework의 핵심 개념은 의존성 주입(Dependency Injection)관점 지향 프로그래밍(Aspect Oriented Programming)이다.

의존성 주입 (Dependency Injection, DI)

객체 간의 의존 관계를 관리하고 조정하는 데 중점을 두며, 이를 통해 소프트웨어의 모듈화, 테스트 용이성, 유지보수성을 크게 향상시키는 중요한 설계 패턴

  • 객체가 자신이 의존하는 다른 객체를 직접 생성하거나 관리하는 것이 아니라, 외부에서 주입받는 방식으로, 전통적인 제어의 흐름을 반전시키는 제어의 역전 원칙을 기반으로 한다.
  • 객체 간의 의존 관계를 코드에서 직접 관리하지 않고, 외부에서 주입함으로써 컴포넌트 간의 결합도를 낮추고 테스트 용이성을 높인다.

핵심원리

객체가 필요로 하는 의존성을 외부에서 주입받음으로써, 객체의 생명주기와 의존성 관리를 프레임워크에 맡기고, 개발자는 비즈니스 로직에 집중할 수 있도록 하는 것이다.

제어의 역전 (Inversion of Control, IoC)

객체의 생성, 초기화, 의존성 관리 등의 제어 흐름을 애플리케이션 코드가 아닌 IoC 컨테이너가 담당하도록 함으로써, 소프트웨어 설계의 전환점을 제공한다.

개념
애플리케이션의 제어 권한을 애플리케이션 코드에서 IoC 컨테이너로 넘기는 것
즉, 객체의 생성 및 초기화, 그리고 객체 간의 의존성을 IoC 컨테이너가 관리하게 된다.

정리
Spring Framework에서 IoC를 구현하는 주요 방법이 DI이다.
DI는 객체 간의 의존관계를 외부로부터 주입 받는 것이고, 이러한 DI를 IoC컨테이너라고 불리는 Spring Container가 수행하는 것이다.

관점 지향 프로그래밍 (Aspect-Oriented Programming)

공통 관심사(cross-cutting concerns)와 같은 비즈니스 로직과는 별도로 처리해야 하는 관심사를 모듈화하여 코드 중복을 줄이고 유지보수성을 높인다.

  • 객체 지향 프로그래밍의 단점을 보완하기 위해 등장
    • 모든 변수 선언 시 new를 통해 객체를 선언
    • 객체를 재사용한다는 측면에서 효율적이었으나, 공통된 부가기능에 대한 코드가 중복, 반복된다는 단점

관심의 분리

  • AOP는 흩어진 관심사를 모아서 모듈화 시킨다.
    • 여기저기에 흩어져서 반복되는 코드를 흩어진 관심사라고 생각한다.
    • 중복된 코드를 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용한다.
  • 기능을 비즈니스 로직과 공통 모듈로 구분한 후에 개발자의 코드 밖에서 필요한 시점에 비즈니스 로직에 삽입하여 실행되도록 한다.
    • 핵심관점(비즈니스 로직) + 횡단관점(트랜잭션, 로그, 권한 체크, 인증, 예외 처리 등)으로 관심의 분리를 실현

정리
OOP에서는 공통적인 핵심 기능을 각 객체의 종단으로 입력했다면, AOP는 핵심 기능에서 중복되는 공통적인 기능을 종단간으로 삽입할 수 있도록 한 것이다.
DI가 의존성(new)의 주입이라면, AOP는 기능(logic)의 주입이라고 할 수 있다.

Spring Container (IoC Container)

어플리케이션의 객체를 관리하고, 의존성을 주입하며, 객체 간의 상호작용을 조율하는 중심적인 역할을 수행하는 핵심 구성 요소이다. 스프링 컨테이너는 의존성 주입제어의 역전 원칙을 기반으로 작동한다.

핵심 기능

  • 빈(Bean)객체의 생성, 초기화, 설정, 그리고 의존성 관리이다.
  • 실질적으로 요청을 처리하는 Bean이라는 것을 두고 관리한다.
  • Bean 객체의 생명주기를 관리하며, Bean 객체 간의 의존성을 설정하고, Bean 객체의 생성 및 초기화 작업을 자동으로 수행한다.

Bean 객체

  • Spring Container가 관리하는 자바 객체로서, 스프링 애플리케이션의 구성 요소

BeanFactory

IoC 컨테이너의 기본 구현체로서, 빈(Bean)이라고 불리는 애플리케이션 객체의 생성, 관리, 의존성 주입을 담당하는 핵심 구성 요소이다. BeanFactory는 애플리케이션의 구성 요소를 관리하며, 객체 간의 결합도를 낮추고 모듈화된 구조를 구현하는 데 중요한 역할을 한다.

주요 기능
빈의 생명주기 관리와 의존성 주입
빈을 초기화할 때 필요한 의존성을 자동으로 주입

  • 애플리케이션 실행 중에 여러 빈이 동일한 의존성을 공유할 수 있도록 싱글톤(Singleton) 빈을 기본으로 지원한다.

Bean

IoC컨테이너가 관리하는 Java 객체로, 애플리케이션의 구성 요소로서 중요한 역할을 한다. Spring Container의 BeanFactory에 의해 생성되고 관리되며, 컨테이너는 이 Bean들의 생명주기와 의존성 관리를 책임진다.

  • 모든 구성 요소의 기본 단위로, 서비스, 데이터 엑세스 객체(DAO), 컨트롤러 등 애플리케이션의 다양한 역할을 수행하는 객체들이 모두 Bean으로 정의된다.
  • 싱글톤 범위가 기본 설정으로, 컨테이너 내에서 특정 빈의 인스턴스가 하나만 존재하도록 보장한다.

ApplicationContext

빈 팩토리를 상속받아 확장한 IoC 컨테이너로, 스프링 어플리케이션 전반에 걸쳐 모든 구성 요소를 관리, 제어하고, 다양한 기능을 제공하여 애플리케이션 개발의 생산성을 높이는 데에 중요한 역할을 한다. 단순히 Bean을 생성하고 관리하는 기능을 넘어, 애플리케이션 전반에 걸친 다양한 기능을 지원하는 종합적인 컨테이너로서의 역할을 수행한다.

  • 별도의 설정 정보 (ex @Configuration 이 적용된 클래스) 를 참고하고 IoC를 적용하여 빈의 생성, 관계 설정 등의 제어 작업을 총괄한다.
  • 애플리케이션 레이어 통합을 지원하며, 데이터베이스 연동, 트랜잭션 관리, 웹 애플리케이션 설정 등을 하나의 컨텍스트에서 통합 관리할 수 있도록 도와준다.
  • 웹 컨텍스트에 맞춘 WebApplicationContext를 통해 서블릿(Servlet)과 통합된 설정을 관리한다.
  • 환경 프로파일을 관리하여, 애플리케이션 실행 환경에 따라 빈 설정을 다르게 구성할 수 있는 기능을 제공한다.

설정 방식
ClassPathXmlApplicationContext : XML 설정 파일을 사용
FileSystemXmlApplicationContext : 파일 시스템에서 XML 설정 파일을 읽어옴
AnnotationConfigApplicationContext : 어노테이션 기반의 설정을 지원

Servlet 과 Servlet Container

일반적으로 웹 애플리케이션을 사용할 때, 웹 서버는 클라이언트(웹 브라우저)의 요청을 받아서 이를 처리하고, 처리된 결과를 클라이언트에게 반환한다.

Web Server

  • 각 요청마다 개별적인 HTTP 요청을 처리해 각각의 문서를 반환했다.

WAS

  • 동적 웹 페이지에서는 서버 측에서 연산을 수행하고, 그 결과를 하나의 페이지로 합쳐서 보여주는 방식이 사용된다. 즉, 클라이언트가 요청을 보내면 서버에서 필요한 처리를 하고, 그 결과를 하나의 응답으로 묶어서 보내주는 방식

Servlet

자바 언어를 사용해서 웹 페이지를 동적으로 생성하기 위한 기술 사양(명세) 인터페이스
웹 프로그래밍에서 클라이언트 요청을 처리하고 처리 결과를 클라이언트에게 전송하는 기술

  • 자바로 작성된 서버 측 프로그램으로, 클라이언트의 요청을 처리하고 응답을 생성하는 역할을 한다.
  • 주로 HTTP 요청을 처리하는 데 사용되며, 요청을 처리하는 메서드(doGet(), doPost()등)를 통해 클라이언트와의 상호작용을 처리한다.
  • 예를 들어, 사용자가 웹 브라우저에서 특정 URL을 요청하면, 서버는 서블릿을 실행하여 그 요청에 맞는 작업을 처리하고 결과를 반환한다.

JSP

HTML 안에 자바 코드를 삽입하게 해주는 기술로, 서블릿과 함께 사용된다. JSP 파일은 기본적으로 HTML을 렌더링하는 데 사용되지만, 동적인 데이터를 삽입하거나 서블릿과의 연동을 통해 웹 페이지를 동적으로 생성할 수 있다.

  • JSP는 서블릿으로 변환되어 실행된다. JSP 파일이 요청되면, 서블릿 컨테이너는 이 JSP를 서블릿으로 변환한 후 실행하고 그 결과를 클라이언트에게 반환한다.

서블릿과 JSP

  • 서블릿은 주로 비즈니스 로직을 처리하고, JSP는 주로 프레젠테이션(화면 표시)을 담당한다.
  • 서블릿은 요청을 받아서 데이터 처리를 한 후, 그 결과를 JSP 페이지에 전달하여 화면에 표시되게 한다.
  • 서블릿은 서버의 백엔드 역할을 하며, JSP는 클라이언트에게 보여주는 프론트엔드 역할을 한다.

Servlet Container

서블릿을 관리해주는 컨테이너로, 대표적으로 톰캣이 있다. 서블릿 컨테이너는 클라이언트의 요청을 받아주고 응답할 수 있도록 객체를 생성하여 웹 서버와 소켓을 만들어 통신한다.

  • 서블릿을 실행하고 관리하는 환경을 제공한다.
  • 서블릿의 생명주기 관리, HTTP 요청 처리, 서블릿 매핑 등을 담당한다.
  • 예를 들어, 서블릿 컨테이너는 클라이언트의 요청을 받아서 해당 서블릿으로 전달하고, 서블릿이 작업을 마친 후 결과를 클라이언트에게 반환하는 역할을 한다.
  • Tomcat과 같은 서버가 대표적인 서블릿 컨테이너

web.xml

서블릿 컨테이너가 구동될 때 필요한 설정들을 저장해둔 파일로, 배포 설명자(Deployment Descriptor) 라고도 부른다. 웹 애플리케이션에서 사용하는 환경변수를 등록할 수 있다.

  • 서블릿을 정의하고, 사용자가 요청한 URL을 분석하여 어느 서블릿에 대해 요청을 한 것인지 찾는다.
  • 서블릿이나 애플리케이션의 초기화 파라미터를 설정할 수 있다.

Spring

(톰캣이라는 서블릿 컨테이너도 있음. 이 그림 밖에 큰 박스가 있다고 생각하면 되고 그게 톰캣)

Dispatcher Servlet

클라이언트가 HTTP 요청을 보내면, 어떤 메서드와 매핑되어있는지 보고 해당 요청을 적절한 컨트롤러로 분배하는 역할을 하는 클래스
서블릿 컨테이너로부터 들어오는 모든 요청을 Presentation Layer 제일 앞에 두고 전처리를 담당하는 중앙 제어점(Front Controller)이다.

  • Spring MVC에서의 프론트 컨트롤러로서, 모든 HTTP 요청은 이 서블릿을 통해 들어오고, 요청을 처리할 핵심적인 역할을 한다.

왜 사용할까?
URL마다 서블릿을 등록하는 번거로움을 피하고, 요청을 효율적으로 처리할 수 있다.

HandlerMapping

Handler Mapping은 요청 URL에 따라 어떤 컨트롤러(Handler)를 호출할지 결정한다.

  • RequestMappingHandlerMapping 이라는 클래스를 통해 요청 URL과 적합한 컨트롤러 메서드를 매핑한다.
  • 예를 들어, /user라는 요청이 오면, @RequestMapping("/user")이 선언된 메서드를 찾아 해당 메서드를 실행한다.

역할

  • 요청 URL을 보고 해당 요청을 처리할 컨트롤러와 메서드를 찾아서 실행한다.
  • 이 과정에서 컨트롤러 메서드에 전달해야 하는 파라미터 값들도 적절히 매핑된다.

ViewResolver

컨트롤러가 반환한 뷰 이름을 실제 뷰 파일로 변환해주는 역할을 한다.

  • 예를 들어, 컨트롤러가 "greeting"이라는 뷰 이름을 반환하면, ViewResolver는 이를 실제 JSP 파일이나 템플릿 파일로 변환하여 응답을 생성한다.

역할

  • DispatcherServlet이 처리한 결과(모델 데이터와 뷰 이름)를 받아 실제 뷰로 렌더링한다.
  • 뷰 템플릿 파일을 찾아서 이를 HTTP 응답의 바디에 포함시켜 클라이언트에게 반환한다.

정리

DispatcherServlet은 Spring MVC에서 모든 요청을 처리하는 중앙 서블릿으로, 요청을 핸들러 매핑을 통해 적절한 컨트롤러로 전달하고, 그 결과를 모델과 함께 반환하고, 뷰 리졸버를 통해 뷰 파일로 변환하여 응답을 생성합니다.

MVC Pattern

애플리케이션을 모델, 뷰, 컨트롤러라는 3가지 구성요소로 분리한 아키텍처 디자인 패턴

Model
애플리케이션의 데이터와 비즈니스 로직을 처리한다.

View
모델에 있는 데이터를 사용자에게 데이터를 보여주고, 컨트롤러로 데이터를 전달한다.
데이터를 직접적으로 처리하지 않고, 단지 보여주기만 한다.

Controller
클라이언트 측의 요청을 처리하고, 그에 따른 모델에 데이터를 업데이트하거나, 요청에 따른 적절한 View에 넣어서 전달한다.

Spring Boot

Spring Framework의 생태계에서 중요한 위치를 차지하는 프로젝트로, 복잡한 Spring 애플리케이션 설정 과정을 단순화하고 개발자의 생산성을 크게 향상시키기 위해 설계되었다.

  • Spring Framework를 기반으로 한 애플리케이션 프레임워크로서, Spring 애플리케이션을 쉽고 빠르게 개발할 수 있도록 도와주는 도구
  • Spring Framework의 많은 프로젝트 들 중 하나로서, 기존 Spring이 내재하고 있던 복잡한 설정(Configuration)을 추상화하고 자동으로 구성할 수 있도록 도와준다.

Component Scan

빈으로 등록될 준비를 마친 클래스들을 스캔하여, 빈으로 등록해주는 것이다. (@Configuration, @Repository, @Service, @Controller, @RestController 포함)

  • @ComponentScan@Component가 붙은 모든 클래스를 스프링 빈으로 등록한다.

  • 메인 클래스에 붙어 있는 @SpringBootApplication은 크게 3가지가 합쳐진 것이라고 생각할 수 있다.

    1. @SpringBootConfiguration
    2. @ComponentScan
    3. @EnableAutoConfiguration

@EnableAutoConfiguration
AutoConfiguration은 결국 Configuration이다.
즉, Bean을 등록하는 자바 설정 파일이다.
스프링 부트에서 필요한 자동설정에 관한 설정을 해준다. ComponentScan을 먼저 진행한 후에 자동설정(Auto Configuration)을 한다.

@SpringBootConfiguration
단순히 Configuration 어노테이션이 적용된 빈임을 나타내는 어노테이션이다.

SOLID 개발 원칙

단일 책임 원칙, SRP (Single Responsibility Principle)

하나의 클래스는 하나의 기능만, 하나의 책임만을 가져야 하며, 클래스는 그 책임을 완전히 캡슐화 해야 한다.

개방 폐쇄 원칙 OCP (Open Closed Principle)

확장(기능 추가)에는 열려있고, 수정에는 닫혀있어야 한다. 기능의 변경이 있을 때 코드를 확장하여, 기존 코드의 수정을 최소화한다. 기존 코드는 변경하지 않고 기능을 추가할 수 있도록 설계해야 한다.

리스코프 치환 원칙 LSP (Liskov Substitution Principle)

자식 클래스를 부모 클래스로 문제없이 바꿀 수 있어야 한다. 어떠한 클래스의 서브 타입은 반드시 기반 타입으로 교체될 수 있어야 한다.

예를 들어, Person이라는 클래스와 Person을 상속받은 Bob 클래스가 있을 때, Person 클래스에 있는 walk() 메서드를 오버라이딩한 Bob 클래스의 walk()메서드에서 뜬금없이 fly와 관련된 메서드가 정의되면 안된다는 것이다.

인터페이스 분리 원칙 ISP (Interface Segregation Principle)

하나의 인터페이스는 하나의 기능만 가지고 있어야 한다. 여러 개로 분리된 인터페이스가 하나의 범용적인 인터페이스보다 낫다. 클라이언트가 사용하지 않는 메서드에 의존하지 않도록 인터페이스는 특정 클라이언트에게 맞게 세분화해야 한다.

예를 들어 Animal 인터페이스에 walk(), fly(), swim() 메서드를 두고, Cat이라는 클래스가 Animal 인터페이스를 구현한다. 이러면 고양이 클래스에게 필요없는 메서드가 생긴다. 그래서 Eatable(), Flyable(), Swimmable() 이라는 인터페이스로 세분화하고 다중 구현하는 것이다.

의존 역전 원칙 DIP (Dependency Inversion Principle)

의존관계를 맺을 때 변하기 쉬운 구체적인 것보다 잘 변하지 않는 추상적인 것에 의존해야 한다. 즉, 구체적인 구현 클래스보다 추상적인 추상클래스, 인터페이스에 의존하라는 것이다.
고수준 모듈이 저수준 모듈에 의존하지 말고 둘 다 추상화에 의존해야 한다. (구현이 아닌 추상화에 의존)

참조를 하면 의존관계가 생긴다고 말한다. 이 때 구현 클래스보단 추상 클래스나 인터페이스에 의존하자.

느낀 점

우와... 오늘 정말.. 내용이 너무 많았다. 처음 하다보니 뭔가 흡수해야 할 게 많았던 것 같다. 그래도 한 번 쭉 정리하고나니 이해가 좀 된다 ! 오늘 실습에서 했던 내용은 헷갈리긴한데.. 스프링부트로 직접 구현할 땐 이렇게 안 한다고 하니 다행이다.

오늘 내용은 너무 많아서 정리했지만,, 다시 한 번 더 봐야할 것 같다. 그리고,, 아직 스프링 부트 실습은 시작도 안 했지만, 지금까지는 재미있는 것 같다 ㅎㅎ 앞으로가 아주 기대가 되는군 !

파이팅하고 남은 오늘 하루도 파이팅해야지 :) 내일 목요일 두근두근

0개의 댓글