소프트웨어 개발을 하다보면 의존성이란 단어가 참 많이 나오는데,
객체 지향을 위한 SOLID 원칙 중 5번째인 D(Dependency Inversion Princilple)에서도 의존성이 나온다.
먼저 의존 역전 원칙을 어떻게 소개하는지 살펴보자.
1. 의존 역전 원칙(Dependency Inversion Principle)
먼저, 의존성이 무엇인지 파악해보자.
" the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details." - Wikipedia (https://en.wikipedia.org/wiki/Dependency_inversion_principle)
의존 관계에 있어서, 고수준 모듈이 저수준 모듈의 구체적 디테일에 독립되어야 한다는 것이다.
- "High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces)." 고수준 모듈은 저수준 모듈의 어떤 것도 import해서는 안되고, 추상에만 의존해야 한다.
- "Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions."
추상은 디테일에 의존해서는 안된다. 구체적 구현은 추상에만 의존해야 한다.
어려운 수능 국어 지문을 보는 느낌이다.
단어 하나 하나들을 정리해보자.
- 고수준 모듈 : 해당하는 모듈을 만들 때, 다른 모듈이 필요한 모듈 (A 모듈이라 하자.)
- 저수준 모듈 : 다른 모듈을 만들 때 참조가 되는 모듈. (B 모듈이라 하자.)
- 여기서 생기는 의존관계? A 클래스의 안에서 B 클래스를 사용할 때, 의존성이 있다고 한다.
- 추상과 구체에 대해서는 앞으로 설명에서 이어서 진행하겠다.
2. 의존성의 형성
A라는 모듈과 B라는 모듈에 대해서 다음과 같이 코드의 예시를 들어보겠다.
public class ModuleA{
ModuleB module; // 모듈A는 모듈B에 의존하고 있다.
public ModuleA() {
this.module = new ModuleB("Hello");
}
public void methodA() {
module.methodB(); // 모듈 B의 구체적인 메소드에 의존하고 있다.
}
}
public class ModuleB{
String string;
public ModuleB(String string){
this.string = string;
}
public void methodB() {
logic();
}
}
이렇게 되어 있을 때, 모듈 A는 지금 모듈 B에 너무나 많이 의존하고 있다.
정확히는, 모듈 B의 구체적인 특성에 너무나 많이 의존하고 있게 된 것이다.
만에 하나 로직이 바뀌게 되거나 모듈 A의 필드를 모듈B가 아닌 비슷한 특성을 가진 moduleC가 필요하거나
더 많은 module로 갈아끼워야하는 순간이 온다면, 로직을 일일이 바꿔야 한다.
왜냐하면 모듈A는 모듈 B라는 구현체 클래스와 모듈 B의 특정 메서드에 많은 의존을 하기 때문이다.
따라서 모듈 A와 모듈 B 사이의 응집력이 너무 높아지게 된 것이다.
3. 의존 역전 원칙
그렇기에 모듈 A가 모듈 B를 덜 의존하기 위해서 인터페이스를 사용한다.
public interface IModule {
void methodB();
}
그리고 아래와 같이 바꿔주기만 하더라도 의존성이 한층 더 낮아진다.
public class ModuleA{
IModule module; // 모듈A는 모듈B에 의존하고 있다.
public ModuleA() {
this.module = new ModuleB("Hello");
}
public void methodA() {
module.methodB(); // 모듈 B의 메서드가 아닌,
//Interface에 정의된 메서드의 구체화된 메서드를 채택하는 방식으로 덜 의존하게 된다.
}
}
그러나 여전히 moduleB라는 구현체 클래스 그 자체에 의존하고 있다.
4. 의존성 주입을 통한 의존 역전 원칙
SOLID원칙이 말하는 의존 역전 원칙이라는 것은 moduleA에서 구현체를 아예 선택하지 않는 방식이 된다.
module을 필드로 사용해서 모듈 B를 생성하려면 무조건 언젠가는 new 를 통한 구현을 해야할텐데???
라는 생각이 들었지만 의외로 해답이 간단해서 놀랐다.
module A를 생성할 때 파라미터를 통해서 구현체를 주입하면 된다.
public class ModuleA{
IModule module; //선언만 해두고, 구현체는 절대 선택하지 않는다
public ModuleA(IModule module) {
this.module = module; // 파라미터로 module이라는 구현체가 들어오게 되는것이다.
}
public void methodA() {
module.methodB();
}
}
--------main method에서--------------
IModule module = new ModuleB();
ModuleA moduleA = new ModuleA(module); // 구현체 ModuleB를 집어넣어줌
이와 같은 방식을 의존성 주입 이라고 한다.
그리고 이렇게 기존에 있었어야 할 의존성을 비틀어버리는 방식을 사용하라는 것이 의존 역전 원칙이 되는 것이다.
의존하지 않게끔 해서 응집도를 낮추고, 유지 보수때 쉽게 쉽게 리팩토링이 가능하게 된다.
물론 의존성을 아예 없애버리기 위해서 무차별 인터페이스를 설정해서 사용한다면
코드의 관리와 유지, 보수가 오히려 더 힘들 수도 있기 때문에
너무 많은 의존 역전 법칙의 적용과 의존성 주입은 삼가해야한다.
참고로 지금은 생성자를 통해서 의존성을 주입하게 됐지만 위에 적어놓은 field 주입 방식 또한 의존성 주입의 방식중 하나이고, 그 밖에 setter를 통해서 의존성을 주입할 수도 있다.
5. Spring Framework가 관리해주는 의존성
Spring Framework는 자바를 통한 웹 개발을 편하게 해주기 위해서 사용되는 프레임워크이다.
위의 자바에서는 우리가 직접 언제 의존할지를 결정하고, 더 의존할지와 덜 의존할지를 결정해야 했지만,
Spring은 의존성도, 생성자도, 생성 시점도 설정만 해둔다면 알아서 해준다.
@Controller
@RequestMapping(value="/users")
public class UserController {
@Autowired // 이 방식으로 bean을 주입
private IService userService; // 새로 생성하지 않아도 알아서 등록이 된다.
@GetMapping("/detail")
public String detail(Model model) {
User retrieved = userService.findByName("CY");
model.addAttribute("name", retrieved.getName());
return "/users/detail";
}
}
그와 같이 사용되는게 쉬운 이유가, Spring에서는 Bean이라는 클래스를 싱글톤으로 다루기 때문이다.
즉, 생성은 딱 한번만 이루어지고, 그 이외의 생성은 이루어지지 않도록 프레임워크가 알아서 설정한다.
가령 위와 같이 @Controller 어노테이션이 달려있다면,
Spring Container 내에서 이 UserController는 이미 싱글톤 객체로 유일하게 등록이 되어 있다. (생성자 및 시점 지정)
그리고 @Autowired 어노테이션을 필드 위에 붙일 경우, 생성자나 필드에 new를 통해 굳이 구현하지 않아도
IService에 @Service어노테이션이 달려있는 Service라는 Bean을 싱글톤으로 다룬다.
그렇기에 의존성을 부여하는 시점 또한 우리가 따로 관리하지 않아도 된다. (의존성 설정)
1. Spring Framework
- Spring은 Java 애플리케이션 개발을 돕는 오픈 소스 프레임워크로, 주로 Dependency Injection (DI), Aspect-Oriented Programming (AOP), Transaction Management, 그리고 다양한 모듈을 통해 엔터프라이즈급 애플리케이션을 쉽게 개발할 수 있도록 돕습니다.
- Spring은 애플리케이션 레벨에서 다양한 기능을 제공하며, 웹 애플리케이션을 쉽게 만들기 위해 Spring MVC라는 모듈을 제공합니다. 이는 MVC 패턴을 기반으로 하여, 컨트롤러와 뷰를 관리하고 HTTP 요청을 처리합니다.
- Spring은 일반적으로 POJO (Plain Old Java Objects) 기반의 개발을 장려하며, Bean과 Dependency Injection을 통해 컴포넌트 간의 의존성을 관리합니다.
2. Spring Boot
- Spring Boot는 Spring을 더 쉽게 사용할 수 있도록 만들어진 확장된 프레임워크입니다. Spring의 복잡한 설정을 자동으로 해주고, 개발자가 보다 쉽게 애플리케이션을 설정하고 실행할 수 있도록 돕습니다.
- Spring Boot는 자동 설정(Autoconfiguration) 기능을 통해 개발자가 일일이 설정할 필요 없이, Spring 애플리케이션을 빠르게 시작할 수 있게 해줍니다. 또한, 내장된 Tomcat 웹 서버를 사용해 별도의 서버 설치 없이 애플리케이션을 실행할 수 있습니다.
- 주요 특징으로는 자동 설정(Autoconfiguration), 스타터 의존성(Starter Dependency), 프로덕션 준비 기능 등이 있습니다.
3. Tomcat (서블릿 컨테이너)
- Apache Tomcat은 Java 서블릿과 JSP(JavaServer Pages)를 실행할 수 있는 서블릿 컨테이너입니다. 웹 애플리케이션 서버의 일종으로, Java 웹 애플리케이션이 클라이언트로부터의 HTTP 요청을 받아들여 처리하는 역할을 합니다.
- Tomcat은 Java EE 표준의 일부인 Servlet과 JSP 사양을 구현한 서버입니다. Tomcat은 기본적으로 HTTP 요청을 처리하는 엔진이며, 서블릿들을 통해 요청을 처리하고 응답합니다.
4. Servlet
- Servlet은 Java EE의 웹 애플리케이션 컴포넌트로, HTTP 요청을 받아 응답하는 자바 클래스를 의미합니다.
- **HttpServlet**을 확장하여 웹 애플리케이션에서 요청을 처리하는데, 클라이언트가 보낸 HTTP 요청을 받고, 해당 요청에 맞는 응답을 반환하는 역할을 합니다.
- Spring에서 **DispatcherServlet**은 Spring MVC의 중심으로, 모든 HTTP 요청을 받아 적절한 컨트롤러로 라우팅합니다. 이를 통해 MVC 패턴을 구현하며, 중앙집중식으로 요청을 처리하는 Front Controller 역할을 합니다.
5. Bean
- Spring Bean은 Spring 애플리케이션에서 관리되는 객체를 의미합니다. Spring은 IoC (Inversion of Control) 컨테이너를 통해 애플리케이션의 객체 간의 의존성을 자동으로 관리합니다.
- Bean은 애플리케이션의 컴포넌트로 등록된 객체로서, 의존성을 DI(Dependency Injection) 방식으로 주입받고, Spring 컨테이너에서 생명주기를 관리합니다. 이 컨테이너가 Spring IoC Container입니다.
6. Container
- Spring Container(또는 IoC 컨테이너)는 애플리케이션에서 사용하는 객체(Bean)들을 관리하고, 의존성을 주입하는 역할을 합니다.
- Spring Container는 애플리케이션이 시작되면 정의된 Bean을 인스턴스화하고, 그들의 의존성을 해결하며, 필요한 경우 Bean의 생명주기를 관리합니다.
- Tomcat과 같은 서블릿 컨테이너는 서블릿과 JSP를 실행하고 관리하며, Spring Container는 애플리케이션 레벨에서 Bean을 관리하는 역할을 수행합니다.
각 개념의 계층 구조
계층 구조 설명
- Spring Boot는 애플리케이션의 진입점으로, 자동 설정 및 Tomcat 내장 서버를 포함하여 전체 애플리케이션을 쉽게 실행할 수 있는 환경을 제공합니다. Spring Boot는 Spring Framework의 상위 레이어에 있으며, Spring MVC와 같은 다양한 Spring 모듈을 포함합니다.
- Spring Framework는 애플리케이션 개발의 핵심으로, DispatcherServlet과 같은 핵심 컴포넌트를 제공하며, 모든 요청을 처리하는 중앙 컴포넌트입니다.
- DispatcherServlet은 HTTP 요청을 받아서 Spring 애플리케이션의 다양한 핸들러로 라우팅하는 역할을 합니다. 이 서블릿은 Spring MVC에서 Front Controller로 사용됩니다.
- Servlet은 Tomcat과 같은 서블릿 컨테이너에서 실행되며, HTTP 요청을 처리하고 응답을 반환하는 역할을 합니다. Spring에서 사용되는 서블릿인 DispatcherServlet이 그 예입니다.
- Tomcat은 서블릿 컨테이너로, Java 서블릿과 JSP 페이지를 실행하고 HTTP 요청을 처리하는 데 사용됩니다. Tomcat은 클라이언트의 요청을 받아서 서블릿이나 JSP로 라우팅하는 역할을 합니다.
- Bean은 Spring IoC 컨테이너가 관리하는 애플리케이션 컴포넌트로, 컨트롤러나 서비스, 리포지토리 등을 Bean으로 등록하여 의존성을 관리합니다. Container는 애플리케이션 내 Bean의 생성, 소멸, DI 주입 등을 관리하는 Spring의 핵심 요소입니다.
이렇게 Spring Boot부터 Tomcat까지의 계층 구조는 애플리케이션이 클라이언트로부터 HTTP 요청을 받아, 내부에서 이를 처리하고 적절한 응답을 돌려주는 일련의 과정에서 중요한 역할을 수행합니다.
3. Bean은 단순한 Java 객체의 래퍼인가?
맞습니다, 하지만 더 나아갑니다. Bean은 단순히 Java 객체를 감싸는 래퍼 역할을 하지만, 중요한 점은 이 Java 객체에 의존성 주입(DI)과 IoC라는 개념이 적용된다는 점입니다.
차이점:
- 일반 객체: Java 객체는 애플리케이션이 직접 생성하고 관리합니다.
- Bean 객체: Spring이 이 객체의 생성, 의존성 주입, 그리고 생명주기를 관리합니다. 이 과정에서 개발자는 객체 간의 의존성이나 생명주기를 직접 처리할 필요가 없습니다.
Bean은 단순히 Java 객체를 감싸는 개념을 넘어서, 의존성 관리와 생명주기 관리까지 담당하는 핵심 컴포넌트입니다.
나의 말:
ChatGPT의 말:
당신이 느끼는 혼란은 Spring이 Bean을 어떻게 관리하는지, 그리고 Java 애플리케이션 내의 모든 객체와 Bean의 관계에 대한 개념에서 오는 것 같습니다. 하나씩 정리해 보겠습니다.
1. Spring의 Bean과 일반 Java 객체의 차이
Java 애플리케이션을 실행하면 수많은 클래스와 객체가 존재하지만, Spring은 모든 클래스나 객체를 Bean으로 등록하지는 않습니다.
Spring에서 Bean으로 등록되는 객체는?
- Spring IoC 컨테이너가 관리하는 객체들만 Bean입니다. 즉, 특정 기능을 제공하는 객체들이 Bean으로 등록됩니다.
- 이 객체들은 주로 서비스 클래스, 리포지토리 클래스, 컨트롤러 클래스 등입니다.
- 모든 Java 객체가 Bean으로 등록되는 것이 아니라, 개발자가 명시적으로 Spring에 등록하거나, Spring이 자동으로 감지한 일부 객체만이 Bean으로 관리됩니다.
2. Bean은 모든 요청에 대해 싱글톤으로 사용되나요?
- 기본적으로, Spring에서 Bean은 싱글톤으로 관리됩니다. 즉, Spring 컨테이너에서 하나의 인스턴스만 생성되고, 애플리케이션 내에서 이를 재사용합니다. 이 싱글톤 Bean은 모든 요청에 대해 동일한 인스턴스가 사용됩니다.
- 싱글톤 스코프는 Spring의 기본 설정이지만, 다른 스코프도 존재합니다. 예를 들어:
- Prototype 스코프: 매번 새로운 인스턴스를 생성합니다.
- Request 스코프: HTTP 요청마다 새로운 Bean 인스턴스를 생성합니다.
- Session 스코프: 세션마다 하나의 Bean 인스턴스를 유지합니다.
Bean의 싱글톤 사용 예시:
- 웹 애플리케이션에서, 데이터베이스와 상호작용하는 서비스 객체는 싱글톤으로 관리됩니다. 모든 클라이언트 요청에 대해 동일한 서비스 객체가 사용되어, 리소스를 효율적으로 관리할 수 있습니다.
3. 모든 Java 객체가 Bean이 되는 것은 아니다
Spring은 애플리케이션의 모든 객체를 Bean으로 등록하지는 않습니다. Bean으로 등록되는 객체는 주로 비즈니스 로직, 데이터 처리, 또는 서비스와 관련된 주요 컴포넌트들입니다. 예를 들어, 애플리케이션 내에서 단순한 헬퍼 클래스나 유틸리티 클래스 등은 Bean으로 관리되지 않을 수 있습니다.
- Bean으로 등록되지 않는 객체: 일반적인 POJO, 헬퍼 메서드가 있는 유틸리티 클래스, 애플리케이션의 특정 부분에서만 사용되는 로컬 객체들은 Bean이 아닐 수 있습니다.
4. 의존성 주입과 Bean 관리
Spring은 Bean 간의 의존성을 주입(DI)을 통해 관리합니다. 의존성 주입은 객체 간의 관계를 컨테이너가 관리하는 방식으로, 개발자가 직접 객체를 생성하거나 관리하지 않고, Spring이 자동으로 연결해줍니다.
- 예를 들어, 서비스 객체가 리포지토리 객체에 의존하고 있으면, Spring은 해당 서비스 객체를 Bean으로 생성할 때 리포지토리 객체를 자동으로 주입해 줍니다. 이 과정에서 싱글톤 Bean은 한 번만 생성되어 여러 곳에서 재사용됩니다.
요약
- 모든 객체가 Bean이 되는 것은 아닙니다. Spring 컨테이너가 관리하는 특정 객체들만 Bean으로 등록되며, 이는 주로 애플리케이션의 핵심 기능과 관련된 컴포넌트들입니다.
- Bean은 기본적으로 싱글톤으로 관리되지만, 필요에 따라 다른 스코프로 설정할 수도 있습니다.
- Spring은 **의존성 주입(DI)**을 통해 Bean 간의 관계를 관리하고, 개발자가 직접 객체 생성을 처리할 필요를 없앱니다.
이러한 방식은 애플리케이션의 모듈성을 높이고, 코드의 재사용성을 증대시키며, 유지보수성을 크게 향상시킵니다.
나의 말:
ChatGPT의 말:
맞습니다! Spring의 Bean은 기본적으로 매 요청마다 재생성되거나 삭제되지 않습니다. 특히, 싱글톤(Singleton) 스코프를 사용할 경우, Bean은 한 번만 생성되어 애플리케이션이 종료될 때까지 유지됩니다. 매 요청마다 새로운 Bean을 생성하거나 삭제하지 않죠.
1. 기본 스코프: 싱글톤(Singleton)
- Spring의 기본 Bean 스코프는 싱글톤입니다. 즉, 애플리케이션이 시작될 때 해당 Bean이 한 번 생성되고, 그 인스턴스는 애플리케이션 전체에서 공유됩니다.
- 싱글톤 스코프의 Bean은 애플리케이션이 종료될 때까지 재생성되지 않으며, 같은 인스턴스가 매 요청마다 사용됩니다.
예시:
위의 예시에서 MyService Bean은 애플리케이션이 실행될 때 한 번만 생성되며, 이후 모든 요청에 대해 동일한 객체가 사용됩니다.
2. 다른 스코프의 Bean
Spring에서는 싱글톤 외에도 여러 스코프를 지원합니다. 특정 상황에서는 매 요청마다 Bean을 재생성하거나 특정 조건에 따라 생성할 수 있습니다. 아래는 주요 스코프들입니다:
- Prototype 스코프: 매번 새로운 Bean 인스턴스를 반환합니다. Bean이 요청될 때마다 새로운 객체가 생성됩니다.Prototype 스코프의 Bean은 주로 상태가 필요하거나 매번 다른 객체를 사용해야 할 때 활용됩니다. 그러나 일반적인 웹 요청 처리에서는 Prototype Bean을 매 요청마다 새로 생성하는 것은 비효율적일 수 있습니다.
-
@Scope("prototype") @Service public class MyPrototypeService { // 매번 새로운 인스턴스가 생성됨 } -
코드 복사
- java
- Request 스코프: HTTP 요청마다 새로운 Bean 인스턴스를 생성합니다. 이 스코프는 웹 애플리케이션에서만 사용되며, 각 클라이언트 요청에 대해 Bean이 새로 생성되고 요청이 끝나면 Bean이 소멸됩니다.
코드 복사@Scope("request") @Component public class MyRequestBean { // 매 HTTP 요청마다 새로운 인스턴스 생성 }- java
- Session 스코프: 각 세션마다 하나의 Bean 인스턴스가 생성되고 유지됩니다. 클라이언트와 서버 간의 세션이 유지되는 동안 동일한 Bean 인스턴스를 사용합니다.
코드 복사@Scope("session") @Component public class MySessionBean { // 세션당 하나의 인스턴스가 유지됨 }- java
3. Bean의 생명주기
- 싱글톤 스코프의 Bean은 애플리케이션이 시작될 때 컨테이너에 의해 생성되고, 애플리케이션이 종료될 때까지 유지됩니다.
- Prototype, Request, Session 스코프의 Bean은 요청 또는 세션 등의 조건에 따라 생성 및 소멸됩니다.
4. 요약
- 싱글톤 스코프(기본 스코프): Bean은 애플리케이션 전체에서 하나의 인스턴스만 생성되고, 애플리케이션 종료 시까지 유지됩니다. 매 요청마다 새로운 Bean이 생성되거나 삭제되지 않습니다.
- 다른 스코프들(예: Prototype, Request, Session): 특정 요구 사항에 따라 Bean이 매 요청 또는 세션마다 생성되고 소멸될 수 있습니다.
따라서 기본적인 Spring 애플리케이션에서는 Bean이 매 요청마다 삭제되거나 재생성되지 않고, 싱글톤 형태로 유지되며, 동일한 인스턴스를 여러 요청에서 재사용합니다.
나의 말:
ChatGPT의 말:
맞습니다! 개인정보나 요청마다 바뀌는 정보를 다루는 객체는 싱글톤 스코프가 아닌 다른 스코프로 관리하는 것이 일반적입니다. 그 이유는 싱글톤 스코프는 애플리케이션 전체에서 동일한 인스턴스를 공유하기 때문에, 사용자별로 또는 요청별로 다른 데이터를 처리해야 하는 객체에는 적합하지 않기 때문입니다.
개인화된 정보, 요청마다 다른 데이터를 처리해야 하는 경우에는, 주로 Request 스코프나 Session 스코프를 사용합니다. 이러한 스코프들은 각 요청이나 세션에 맞는 새로운 객체 인스턴스를 생성해주기 때문에, 각 클라이언트별로 안전하게 데이터를 처리할 수 있습니다.
스코프별 특징
- Request 스코프
- HTTP 요청당 하나의 인스턴스가 생성됩니다.
- 각 HTTP 요청이 들어올 때마다 새로운 Bean 인스턴스를 생성하며, 요청이 끝나면 해당 Bean 인스턴스는 소멸됩니다.
- 사용 예: 로그인 정보나 사용자의 일시적인 요청 데이터를 처리할 때 사용됩니다. 예를 들어, 폼 제출 요청 데이터를 처리하는 객체에 적합합니다.
java코드 복사@Scope("request") @Component public class UserRequestData { private String requestData; // 요청마다 다른 데이터를 다룰 수 있음 } - Session 스코프
- 각 사용자 세션당 하나의 인스턴스가 생성됩니다.
- 세션이 시작될 때 해당 Bean 인스턴스가 생성되고, 세션이 끝날 때 소멸됩니다. 같은 사용자 세션 동안에는 같은 객체가 유지됩니다.
- 사용 예: 사용자 인증 정보나 세션을 통해 여러 요청에서 같은 데이터를 사용할 때 유용합니다. 예를 들어, 사용자의 로그인 상태와 같은 정보를 관리하는 데 적합합니다.
java코드 복사@Scope("session") @Component public class UserSessionData { private String sessionId; // 세션 당 인스턴스가 유지되므로 사용자별 상태를 관리 가능 } - Prototype 스코프
- 매번 새로운 인스턴스가 필요할 때마다 Bean이 새로 생성됩니다.
- Prototype 스코프는 요청이 올 때마다 새 객체를 반환하지만, 관리 주체는 Spring이 아니라 호출하는 쪽이 됩니다. 주로 짧은 생명주기를 갖는 객체를 필요로 할 때 사용됩니다.
- 사용 예: 상태를 유지하지 않는 객체나 매번 새로운 인스턴스를 사용해야 하는 경우에 적합합니다. 예를 들어, 특정 서비스의 비즈니스 로직에서 임시로 필요한 객체를 Prototype으로 설정할 수 있습니다.
java코드 복사@Scope("prototype") @Component public class TempDataProcessor { // 매번 새로운 인스턴스가 생성됨 }
ChatGPT의 말:
1. Spring Boot에서는 내장 servlet container인 Tomcat을 제공하고 Spring Container가 있음
- 맞습니다. Spring Boot는 기본적으로 내장된 Tomcat을 포함하며, 별도의 설정 없이도 웹 애플리케이션을 실행할 수 있습니다. 또한, Spring Container(Spring IoC 컨테이너)는 애플리케이션의 Bean을 관리하고, 의존성 주입 및 생명주기를 처리합니다.
2. 요청에 대한 응답의 핵심은 DispatcherServlet
- 맞습니다. **DispatcherServlet**은 Spring MVC에서 핵심적인 Front Controller로, 모든 HTTP 요청을 받아서 적절한 컨트롤러로 전달하고, 응답을 구성하여 클라이언트에게 반환하는 역할을 합니다.
3. 핸들러 매핑을 통해 사용할 컨트롤러를 확인
- 맞습니다. Spring의 **핸들러 매핑(HandlerMapping)**은 요청 URI와 매핑된 **컨트롤러(Handler)**를 결정하는 역할을 합니다. 핸들러 매핑은 요청의 경로, 메서드, 헤더 등 여러 조건을 기반으로 적절한 컨트롤러를 선택합니다.
4. 핸들러 어댑터로 요청에 대한 처리를 위임
- 맞습니다. **핸들러 어댑터(HandlerAdapter)**는 핸들러(컨트롤러)를 호출하기 위한 중간 계층 역할을 합니다. 컨트롤러의 유형에 맞는 어댑터가 요청을 처리하도록 위임합니다.
5. 핸들러 어댑터는 컨트롤러(Spring Bean 중 하나) 선택 후, 컨트롤러가 비즈니스 로직 처리를 위한 Bean 객체들을 활용해 서비스와 리포지토리, 더하자면 DB까지 종합한 모델을 구축
- 대부분 맞습니다.
- 핸들러 어댑터는 컨트롤러를 호출하여, 컨트롤러가 비즈니스 로직 처리를 위한 서비스 Bean 및 리포지토리 Bean을 사용합니다.
- 다만 핸들러 어댑터가 컨트롤러를 "선택"하는 것은 아니고, 핸들러 매핑이 컨트롤러를 선택한 후, 핸들러 어댑터가 그 컨트롤러를 호출해 요청을 처리하는 방식입니다.
- Model을 구축하는 부분은 컨트롤러가 처리하며, 주로 비즈니스 로직 수행 후 모델 객체를 반환하거나 뷰로 전달합니다.
6. 그리고 view name을 확인
- 맞습니다. 컨트롤러는 요청을 처리한 후, 보통 ViewName(뷰의 논리적인 이름)을 반환합니다. 이 ViewName은 이후 ViewResolver에 의해 실제 뷰로 매핑됩니다.
7. ViewResolver가 View Template과 Model을 통해 View를 생성하고 이를 반환
- 맞습니다. ViewResolver는 ViewName을 기반으로, 해당 뷰 템플릿(JSP, Thymeleaf 등)을 찾고, Model 객체를 뷰로 전달하여 최종 HTML 등의 응답을 생성합니다. 생성된 뷰는 클라이언트에게 반환됩니다.
0. Filter에 대한 설명
- Filter는 서블릿 컨테이너의 일부로, DispatcherServlet에 도달하기 전에 요청을 처리할 수 있습니다. 주로 요청이나 응답을 가공하거나, 보안 처리, 로깅, 인증, 인코딩 설정 등을 수행할 수 있습니다.
- Filter는 서블릿 스펙의 일부이며, 요청이 컨트롤러에 도달하기 전에 가로채어 전처리 또는 후처리를 수행합니다.
'연재작 > WEB - BE' 카테고리의 다른 글
Spring Bean Deep Dive (0) | 2024.12.02 |
---|---|
디렉토리 구조와 Facade 패턴 (1) | 2024.11.19 |
JVM Runtime Data Area, Singleton과 Race Condition (1) | 2024.11.15 |
Spring bean (2) - Singleton, Bean (0) | 2024.10.11 |
Spring bean (1) - Dispatcher Servlet (Front Controller Pattern) (0) | 2024.10.02 |