Spring Container(IoC Container)
객체 생성과 생명주기를 개발자가 아닌 Spring이 대신 관리해주는 공간
스프링 컨테이너에 의해 관리되는 재사용 가능한 sw 컴포넌트인 bean을 생성 이를 통해 의존관계 연결, 관리를 수행한다.
스프링 빈들의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공한다.
스프링 컨테이너를 통해 원하는 만큼 많은 객체를 가질 수가 있다.
의존성 주입을 통해 애플리케이션의 컴포넌트를 관리할 수가 있다.
@Configuration을 클래스에 붙이면 이 클래스를 설정정보를 사용가능하다.
그리고 클래스 내부에 @Bean을 붙인 메서드를 스프링 컨테이너에 등록하는 것이 가능하다.
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
의존성 주입(Dependency Injection)
객체가 필요로 하는 다른 객체(의존 객체)를 직접 생성하지 않고, 외부에서 전달받는 설계 방식
public class OrderService {
private MemberRepository memberRepository;
}
만약 여기서 다른 레포지토리를 사용하고 싶다면 코드를 수정해야 한다. 이러한 강하게 결합된 클래스를 분리하고 애플리케이션의 실행시점에 객체 간의 관계를 결정함으로써 결합도를 낮추고
유연성을 확보한다. 이 경우 외부에서 memberRepository를 넣는 것을 외부에 맡기게 된다.
- IoC와의 관계
IoC가 조금 더 넓은 개념이라고 볼 수가 있다. IoC를 구현하는 방법이라고 볼 수가 있다.
아래는 DI를 구현한 코드이다.
@Service
public class OrderService {
private final MemberRepository memberRepository;
public OrderService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
제어의 역전(Inversion Of Controll)
객체 생성과 실행 흐름의 제어권을 개발자에서 프레임워크로 넘기는 것
개발자가 직접 Controller을 호출하지 않고 Spring이 그 역할을 해주는 것을 의미한다.
이 제어의 역전으로 변화하는 요구사항에 대한 확장성을 넓힐 수 있고 코드의 결합도가 낮아져 테스트 용이성을 증가시킬 수가 있다. 이 제어의 역전의 대표적인 예시는 두가지가 있는데 첫번째는 위에서 언급한 의존성 주입이다. 의존성 주입을 통해 두번째로는 스프링 프레임워크가 있다. 우리가 흔히 쓰는 라이브러리의 제어권은 우리한테 있지만 프레임워크의 제어권은 프레임워크가 가진다. 스프링의 경우 객체 메서드의 호출을 스프링에게 맞길 수가 있어 유지 보수성을 키울 수가 있습니다.
Servlet
웹요청을 처리하는 클래스이다. http request를 java가 알아듣지를 못한다. 그래서 이것을 java 객체로 변환하는 것이 서블릿이라고 볼 수가 있다. 서블릿은 인터페이스 구조로 되어있다.
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
// 요청 처리
}
}
httpServletRequest로 클라이언트의 요청정보를 받고 클라이언트에 보낼응답을 HttpServletResponse 형에 저장을 한다.
서블렛의 생명주기
- init()
서블릿을 처음 메모리 올릴 때 실행, 서블릿을 초기화하며 처음에 한번만 실행 - service()
요청/응답을 처리, 요청이 GET인지 POST인지 구분, doGet, doPost 메소드로 분기
유일하게 여러번 실행되는 단계 - destroy()
서블릿 종료요청이 있을때 destroy()메서드로 실행
참고
하나의 객체를 여러 요청이 공유하기 때문에 멀티스레드 문제를 잘 다루는 것이 중요하다
그렇지만 사용자가 직접 서블릿을 다루면 코드가 복잡해져 IoC가 필요하다. 이러한 IoC를 반영한 것이 DispatcherServlet이다.
Servlet Container
서블릿을 생성하고 실행하며, http 요청/응답을 관리해주는 서버환경을 의미한다.
대표적인 예시로 Apache Tomcat, Jetty, Undertow가 있는데 Spring boot 환경에서는 Tomcat을 내장하고 있다.
- 통신하는 순서
- 클라이언트 요청 발생
- Tomcat이 요청 받음
- Request/Response 객체 생성
- 적절한 Servlet 호출
- 결과를 HTTP 응답으로 변환
- 클라이언트에게 반환
서블릿 컨테이너는 서버 측에서 동적으로 웹페이지를 생성하기 위해 사용을 하고 서블릿들과 웹서버의 상호작용에서 사용하기 때문에 스프링에서 필수적인 요소라고 보면 된다.
WAS(Web Application Server, Servlet Container)
웹 애플리케이션을 실행시키는 서버, 단순 요청에 대한 정적인 파일을 내리는 것뿐만 아닌 비지니스 로직을 처리한다. nginx와 같은 web서버와 같이 사용하기도 하는데 nginx는 정적인 로직에 집중하고 WAS는 동적인 로직에 집중하여 처리를 하게 된다. Servlet Container을 포함하고 있는 실행환경을 의미한다. http요청을 받아 적절한 Servlet으로 전달하고 실행결과를 다시 http응답으로 만들어준다.
Template Engine
데이터 + 템플릿을 결합하여 동적인 Html을 만들어주는 기술을 의미한다. Html 틀에 서버에서 가져온 데이터(model)을 넣어서 최종 화면을 생성하는 역할이다. 동적으로 html을 구성할 수 있어서 유용하다.
대표적으로 Tyhmeleaf, JSP등이 있다.
model.addAttribute("name", "홍길동");
return "user";
위와 같은 자바로 값을 전달하고 이를 html 틀에 넣어 결정한다.
<h1 th:text="${name}"></h1>
<h1>홍길동</h1>
Dispatcher Servlet

MVC구조의 이 컨트롤러 역할을 하는 핵심 Servlet이다. 모든 http요청을 가장 먼저 받는 진입점이다. 요청을 적절한 Controller로 분배하는 역할을 수행한다.
기존의 Servlet방식은 URL마다 Servlet을 직접 매핑하고 코드가 분산되어서 관리가 어려웠지만 DispatcherServlet의 도입으로 모든 요청을 하나로 모아 공통 로직을 관리하기 쉬워졌다.
View Resolver
컨트롤러가 반환한 객체는 논리적 뷰 이름으로 반환받는데 이를 실제 view로 변환해주는 역할을 수행한다.
- 역할
- 컨트롤러는 특정 뷰를 식별하기 위해 문자열 형태로 뷰 이름을 반환하게 된다.
뷰 리졸버는 이를 실제 뷰 템플릿 파일로 매핑을 한다.
- 컨트롤러는 특정 뷰를 식별하기 위해 문자열 형태로 뷰 이름을 반환하게 된다.
Request Mapping
스프링에서 핵심적인 어노테이션 중에 클라이언트의 HTTP 요청을 특정 컨트롤러 메서드와 연결시켜주는 역할을 수행한다.
쉽게 말하면 URL과 메서드를 매칭시켜주는 역할을 수행한다고 볼 수가 있다.
@RestController
public class MyController {
@RequestMapping("/hello")
public String hello() {
return "Hello World";
}
}
Handler Concept
Spring에서의 Handler란 클라이언트의 요청을 실제로 처리하는 대상을 의미한다 다른 말로는 URL요청을 받아서 비즈니스 로직으로 실행하는 주최이다. @Controller, @RestController안의 요청처리 메서드이다.
- Handler를 사용하는 흐름
- 클라이언트 요청
- DispatcherServlet 실행
- HandlerMapping → Handler 찾기
- HandlerAdapter → 타입과 목적에 맞는 Handler를 찾는다
- Controller에서 Handler를 실행하게 된다.
- ViewResolver → View 반환
- 리턴 타입
handler로 나오는 return은 view기반, REST기반, 비동기 기반에 따라 나뉘지만
실무 기준으로는 다음과 같다.- 웹 페이지 : String + Model
- REST API : ResponseEntity
- 간단 API : @ResponseBody + 객체
참고 : 리펙토링이란?
업데이트와 달리 기존 코도와 나오는 결과는 같아야 한다. 동작하는 코드를 더 좋고 가독성 있게 바꾸는 작업이다. 대전제는 동작하는 코드라서 일단 동작부터 시켜야 한다. -> 동작이 일치해야지 리펙토링이다.
참고 : ctrl + o → override한 메서드 부르는 단축키