Spring에 대한 정리 글

최준호·2022년 1월 15일
0

Spring

목록 보기
22/47
post-thumbnail

📗 Spring이란

Spring이란 IoC(Inversion of Control)AOP(Aspect Oriented Programming)를 지원하는 경량 컨테이너 프레임워크이다.

경량이란

Spring은 가볍고 빠르며 여러개의 모듈로 구성되어 있어 각 모듈은 하나 이상의 jar파일로 구성되어 있다. 이 몇개의 jar 파일만 있으면 개발과 실행이 모두 가능하다.

또한 스프링 프레임워크가 POJO 형태의 객체를 관리하기 때문이다. POJO는 클래스를 구현하는데 특별한 규칙이 없는 단순하고 가벼운 객체이다.

POJO(Plain Old Java Object)란

말 그대로 평범한 옛날 자바 객체를 의미한다. POJO 객체는 따로 요구하는 규칙이 없이 개발자가 마음대로 정의할 수 있다.

예를들어 POJO는 다음과 같은 규칙성을 부여하면 안된다.

  1. 미리 지정된 class를 extends 하는 것
  2. 미리 정의된 인터페이스를 implement하는 것
  3. 미리 정의된 Annotation을 포함하는 것

POJO란 개발자가 하나의 class를 정의할 때 다른 class들과 의존성이 부여되지 않은 순수한 class 그대로 그 자체의 java를 의미하는 것이다.

IoC란 (feat. DI)

IoC란 Inversion of Control으로 직역하면 제어의 역전이다. 제어의 역전이란 기존의 java의 코드를 실행하기 위해서는 개발자가 직접 객체를 생성하고 제어해야했다. 하지만 Spring에서는 이를 개발자가 직접하지 않고 제 3자인 Spring Conatainer에게 위임하여 사용하게 된다.

public Class Test{
    private Test2 test2;
    
    public Test(){
        test2 = new Test2();
    }
}

Test class는 Test2 class를 의존하고 있다. 위 코드는 개발자가 직접 객체를 제어하며 Test 객체는 Test2 객체에게 의존하고 있어라고 표현한 것이다.

그럼 Spring에서 Container에게 객체의 생성을 위임한 코드는 어떨까?

public Class Test{
    @Autowired
    private Test2 test2;
}

Spring으로 프로젝트를 진행해봤다면 많이 본 코드이다. Test2 객체가 스프링 컨테이너에게 관리되고 있고 Bean이라면 @Autowired를 통해 객체를 주입받을 수 있게된다. 이것은 개발자가 직접 객체를 관리하지 않고 스프링 컨테이너에게 객체를 생성하여 해당 객체를 주입시키라고 한것이다.

이렇게 기존 java에서 개발자가 직접 객체를 생성하고 의존성을 주입하던 방식과 다르게 Spring Container에게 객체의 생성과 의존성의 부여에 대한 관리의 책임을 위임한것을 IoC라고 한다.

여기서 DI란?

Spring의 IoC의 개념은 항상 DI(Dependency Injection)와 함께 언급되는데 이 둘의 차이점은 무엇이고 왜 함께 언급되는지 알아보자.

우선 IoC라는 것은 Spring에서 최초로 시작된 개념이 아니다. Spring 이전의 EJB에서도 사용된 개념이다. DI라는 개념 또한 Spring에서 시작된 개념이라기 보다는 미국의 개발자 마틴 파울러는 DI라는 개념을 만들어 IoC라는 범용적인 의미 대신 객체 주입이라는 의미의 단어를 새롭게 만든 것이다. Spring에서는 IoC의 DI라는 방식을 통해 IoC를 더 구체적으로 DI라는 방식을 통해서 의존성 역전 제어를 하고 있다라고 이해하면 될것이다.

의존성 주입이란 의존관계에 있는 객체들이 있을 때, 외부(Spring Container)에서 객체에 레퍼런스를 전달하여 사용하고자 하는 객체에 코드를 사용할 수 있게 한다. 라는 의미로 이해하자.

그럼 DI에 3가지 조건을 살펴보면 더 이해가 하기 쉬워지는데

  1. 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야한다.
  2. 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.
  3. 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 주입해줌으로써 만들어진다.

우리가 Spring에서 Service를 interface로 생성하고 구현체를 작성하는 이유이기도 하다. Service를 class로 작성하여 직접 객체를 생성하고 사용해도 사용할 순 있지만 이는 Spring의 기능을 사용하지 않고 개발자가 직접 객체를 사용하는 것이므로 멍청한 일이다.(나=멍청)

  • 그럼 IoC와 DI의 차이점은 무엇인가??
    IoC는 객체의 흐름, 생명주기관리 등 독립적인 제 3자에게 역할과 책임을 위임하는 방식의 프로그래밍 모델이다. 디자인 패턴에서도 찾아볼 수 있고 다른 컨테이너를 가진 프레임워크에서도 찾아볼 수 있다. 즉 범용적이 표현이다.
    하지만 DI는 인터페이스를 통해 다이나믹하게 객체를 주입하여 유연한 프로그래밍을 가능하게 하는 패턴으로 좀 더 IoC를 구체적으로 표현한 것이다.

AOP(Aspect Oriented Programming)

AOP(관점지향 프로그래밍)는 비지니스 로직 중 반복해서 등장하는 공통 로직을 분리함으로써 음집도가 높은 코드를 작성할 수 있도록 도와준다.


📘 Annotation (@)

@ComponetScan

컴포넌트 스캔은 @Component 어노테이션이 적용된 클래스들을 스캔하여 자동으로 객체를 생성한다. 자동으로 등록된 객체들은 Spring 내에서 단 하나의 객체만을 생성하며 서비스 로직에서 사용되는 객체는 해당 객체의 주소를 복사하여 사용하는 것이다. 이를 singleton이라고 한다.

@Component

스프링 설정 파일에 bean으로 일일히 설정할 필요 없이 @ComponentScan을 적용한 프로젝트라면 @Component로 설정한 class들을 자동으로 컨테이너에 bean으로 등록하여 관리해준다.

@Bean

@Component로 class를 자동으로 컨테이너에 bean으로 등록할 수도 있지만 @Configuration 어노테이션을 통해 bean으로 등록하는 방법도 존재한다.

@Configuration
public cass TestConfiguration{
    @Bean
    public Test test(){
        return new Test();
    }
}

@Configuration 또한 @ComponentScan의 스캔 대상이 되는데 그 이유는

@Component를 내장하고 있기 때문이다. @Configuration는 해당 파일 내부에 @Bean으로 등록한 객체들을 IoC 컨테이너의 bean으로 등록할 수 있다.

bean scope

bean scope란 빈의 생명주기를 나타내는 것이다. Spring의 기본적으로 모든 bean을 singleton으로 생성하여 관리한다.

singleton Spring IoC Container 내에 단 하나의 객체만 존재한다. 이 객체는 컨테이너의 종료까지 유지된다.
prototype 스프링 컨테이너는 빈의 생성과 의존관계 주입까지만 관여하고 그 이후에는 관여하지 않는다. 사용자의 요청이 들어올 때마다 새롭게 객체를 생성한다.
request 요청이 들어오고 종료될때까지만 유효하다.
session 웹 세션이 생성되고 종료될때까지 유효하다.
application 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프이다.

bean init과 destroy

컨테이너에서 객체를 생성하고 객체를 삭제할때 호출하는 임의의 메서드를 지정할 수 있다. 대부분의 init은 객체의 멤버변수를 초기화하는 경우 사용한다. init은 @PostConstruct로 정의할 수 있고 destroy는 @PreDestroy로 정의할 수 있다.

의존성 주입 Annotation

Spring의 의존성 관리

스프링의 가장 중요한 특징은 객체의 생성과 의존관계를 컨테이너가 자동으로 관리한다는 점이다. 스프링은 의존성 관리에 대해

  1. Dependency Lookup(DL)
  2. Dependency Injection(DI)

형태로 지원하고 있다.

DL 의존관계 검색은 객체를 사용하고자 하는 class(=자신이 직접)에서 컨테이너 내부에 등록된 bean을 직접 검색하여 의존성을 주입받고자 하는 방법이다.

DI 각 클래스의 의존성을 자신이 아닌 컨테이너(=제 3자)에서 등록해준다.

@Autowired

주로 변수에 설장하여 해당 타입의 객체를 자동으로 할당한다.

@Qualifier

특정 객체의 이름을 이용하여 의존성 주입을할 때 사용한다.

@Inject

@Autowired와 동일하게 작동한다.

@Resource

@Autowired@Qualifier의 기능을 결합한 어노테이션이다. name 속성을 사용하여 객체의 이름일 이용하여 사용할 수 있다.


📙 Spring에서의 WAS 동작


이미지 출처

WAS는 사용자가 웹 브라우저에서 url 요청이 들어왔을 때

  1. HTTP 요청 메세지를 기반으로 request를 생성
  2. was 내 servlet container에서 해당 url의 서블릿 객체를 생성
  3. request 정보를 갖고 서비스 로직을 실행
  4. 서비스 로직으로부터 생성된 데이터를 담을 response 객체를 생성
  5. url에 대한 서블릿 객체 종료
  6. response 반환

Servlet이란

Spring에서의 서블릿이란 HTTP의 메세지를 자바를 사용하여 웹 페이지를 동적으로 생성할 수 있게 기능이라고 생각하면 좋을거 같다. Servlet은 int(), service(), destroy() 3개의 메서드를 반드시 정의해야한다.

1. `init()` servlet 생성시 호출, servlet 멤버 변수 초기화 및 자원 할당
2. `service()` 실제 서비스 로직 실행
3. `destroy()` servlet을 삭제
/*
Servelte 코드
*/
@WebServlet(urlPatterns = "/test")
public class TestServlet extends HttpServlet {
    //get요청
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //서비스 로직 동작...
    }
    
    //post요청
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //서비스 로직 동작...
    }
}

Servlet Container란 (==Tomcat)

서블릿 컨테이너란 was와 동일한 개념이다.
클라이언트의 요청(Request)가 들어왔을 때 Controller에 정의해둔 서블릿들 중에 어떤 서블릿을 실행할 것인지 제어하고 실행과 종료에 대한 생명주기를 담당한다.


👍 마무리 정리

Client로부터 요청이 들어왔을 때

  1. Web Server의 Request 정보를 WAS 내 DispatcherServlet에서 요청이 가능한 정보인지 Handler Mapping을 통해 조회
  2. 처리할 수 있는 요청이라면 처리할 수 있는 Handler Adapter를 조회
  3. Handler Adapter를 통해 url이 매칭되는 controller 호출(쓰레드 생성)
  4. controller는 bean으로 등록된 service와 respository를 통해 데이터 반환 받음
  5. 반환 받은 데이터가 view로 넘어가는 데이터라면 viewResolver를 통해 View 객체를 반환받고 모델로 넘김
  6. 반환 받은 데이터가 api 형식의 반환되는 데이터라면 MessageConverter를 통해 데이터(객체, text 등)를 만들어서 반환
  7. 반환할 데이터를 Response 객체를 생성하여 담아서 반환하고 3에서 생성된 쓰레드 종료

Context란

context란 해당 개념들을 모아둔 목록이라고 생각하면 편할것 같다.

ServletContext

Servlet에 대한 객체들을 모아둔 Context

ApplicationContext

기존의 BeanFactory의 기능을 확장하여 사용하는 Context
bean 객체들을 모아둔 Context이며 추가적으로 다른 부가 기능을 사용할 수 있다.

DispatcherServlet이란

디스패쳐 서블릿은 Client의 request가 들어왔을 때 가장 먼저 받아 적합한 Controller를 찾아주는 역할을 한다.

참고
Spring 공식 문서
Spring 개념에 대한 글
Ioc와 DI의 개념
bean scope에 대한 개념
Spring Container와 Servlet Container
Dispatcher 개념 Spring 공식문서

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글