Spring
FrontController와 MVC 패턴 개요
웹 애플리케이션을 설계할 때, MVC(Model-View-Controller) 패턴을 활용하면 구조적이고 유지보수가 쉬운 애플리케이션을 만들 수 있음 이 패턴에서 FrontController는 사용자의 요청을 중앙에서 처리하고 적절한 액션을 실행하며, 결과를 클라이언트에게 전달함
현재 FrontController의 구조와 동작
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
public FrontController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
private void doAction(HttpServletRequest request, HttpServletResponse response) {
// 1. 사용자가 무슨 요청을 했는지 추출 및 확인
String uri=request.getRequestURI();
String cp=request.getContextPath();
String command=uri.substring(cp.length());
System.out.println("command : "+command);
// 2. 요청을 수행
ActionForward forward=null;
if(command.equals("/main.do")) {
MainAction mainAction=new MainAction();
forward = mainAction.execute(request, response);
}
else if(command.equals("/boardDetail.do")) {
BoardDetailAction boardDetailAction=new BoardDetailAction();
forward = boardDetailAction.execute(request, response);
}
else if(command.equals("/login.do")) {
LoginAction loginAction=new LoginAction();
forward = loginAction.execute(request, response);
}
else if(command.equals("/joinPage.do")) {
JoinPageAction joinPageAction=new JoinPageAction();
forward = joinPageAction.execute(request, response);
}
else if(command.equals("/join.do")) {
JoinAction joinAction=new JoinAction();
forward = joinAction.execute(request, response);
}
else if(command.equals("/logout.do")) {
LogoutAction logoutAction=new LogoutAction();
forward = logoutAction.execute(request, response);
}
// else {
// ErrorAction errorAction=new ErrorAction();
// forward = errorAction.execute(request, response);
// }
// 3. 응답(페이지 이동 등)
// 1) 전달할 데이터가 있니? 없니? == 포워드? 리다이렉트?
// 2) 어디로 갈까? == 경로
if(forward == null) {
// command 요청이 없는 경우
}
else {
if(forward.isRedirect()) {
try {
response.sendRedirect(forward.getPath());
} catch (IOException e) {
e.printStackTrace();
}
}
else {
RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
try {
dispatcher.forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
현재 FrontController의 문제점:
- MainAction과 같은 액션 객체가 매 요청마다 새로 생성되므로 메모리 낭비가 발생함
- 이로 인해 메모리 사용이 비효율적이며, 객체가 계속해서 생성되고 소멸되기 때문에 성능 저하가 발생할 수 있음
이 때 핸들러 맵핑과 싱글톤 패턴을 활용
핸들러 맵핑과 싱글톤 패턴
핸들러 맵핑은 FrontController가 사용자의 요청을 적절한 액션으로 매핑하는 과정임. 이 과정에서 요청의 URL 패턴을 기반으로 해당 액션을 선택함. 좋은 프레임워크는 핸들러 맵퍼를 사용하여 효율적으로 요청을 처리함. 핸들러 맵핑을 사용하면 컨트롤러가 요청에 따라 적절한 액션 객체를 생성하고 호출할 수 있으며, 이는 프레임워크의 핵심 기능 중 하나임
싱글톤 패턴은 객체를 오직 하나만 생성하고 이를 재사용하는 디자인 패턴임. 이 패턴을 적용하면 메모리 사용을 최적화하고, 자원 낭비 (new연산) 를 줄일 수 있음. FrontController에서 액션 객체를 매번 새로 생성하는 대신, 이미 생성된 객체를 재사용하면 성능이 향상됨
핸들러 맵퍼
package controller.common;
import java.util.HashMap;
import java.util.Map;
public class HandlerMapper {
private Map<String, Action> mapper; // 멤버 변수로 Map을 가짐
public HandlerMapper() { // 생성자 == 멤버 변수 초기화
this.mapper = new HashMap<String,Action>();
// Action Mapping
this.mapper.put("/main.do", new MainAction());
this.mapper.put("/board.do", new BoardAction());
this.mapper.put("/login.do", new LoginAction());
this.mapper.put("/logout.do", new LogoutAction());
}
// 요청을 파라미터로 받고
// 파라미터(key)에 해당하는 액션 반환
public Action getAction(String command) {
return this.mapper.get(command);
}
}
핸들러 맵핑과 싱글톤 패턴을 적용한 FrontController 구조
package controller.common;
import java.io.IOException;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("*.do")
// 톰캣(server)이 구동될때, xxx.do로 끝나는 요청에 대하여 FC를 호출하게됨
public class FrontController extends HttpServlet {
private static final long serialVersionUID = 1L;
private HandlerMapper mappings; // 맵버 변수로 핸들러맵퍼를 갖음(재사용을 위함)
public FrontController() { // frontController 생성자
super();
// FrontController가 생성될 때 핸들러맵퍼도 같이 생성
// new연산을 줄이기 위함(싱글톤 패턴)
this.mappings=new HandlerMapper();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
private void doAction(HttpServletRequest request, HttpServletResponse response) {
// 1. 사용자가 무슨 요청을 했는지 추출 및 확인
String uri=request.getRequestURI();
String cp=request.getContextPath();
String command=uri.substring(cp.length());
System.out.println("command : "+command);
// 2. 요청을 수행
// 요청을 인자로 넘기면 맵핑되어있는 액션이 돌아옴
Action action = this.mappings.getAction(command);
// 해당 액션으로 요청 수행
ActionForward forward = action.execute(request, response);
// 3. 응답(페이지 이동 등)
// 1) 전달할 데이터가 있니? 없니? == 포워드? 리다이렉트?
// 2) 어디로 갈까? == 경로
if(forward == null) {
// command 요청이 없는 경우
}
else {
if(forward.isRedirect()) {
try {
response.sendRedirect(forward.getPath());
} catch (IOException e) {
e.printStackTrace();
}
}
else {
RequestDispatcher dispatcher=request.getRequestDispatcher(forward.getPath());
try {
dispatcher.forward(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
싱글톤 패턴 적용:
- 액션 객체를 한 번만 생성하고, 이후에는 재사용하도록 설계하면 메모리 사용을 절약할 수 있음
- 이를 위해 핸들러 맵핑을 사용하여 액션 객체를 관리하면, 각 요청마다 새로 객체를 생성할 필요 없이 이미 생성된 객체를 재사용할 수 있음
결론
MVC 패턴을 활용하면 웹 애플리케이션의 구조를 명확히 하고 유지보수를 용이하게 할 수 있음. FrontController는 요청을 처리하는 중심 역할을 하며, 핸들러 맵핑과 싱글톤 패턴을 통해 성능을 최적화할 수 있음. 핸들러 맵핑을 통해 효율적으로 액션을 관리하고, 싱글톤 패턴을 적용하여 메모리 사용을 최소화하면 더욱 효율적인 애플리케이션을 개발할 수 있음
'javaboiii의 Spring' 카테고리의 다른 글
Spring - 의존성 주입 (1) | 2024.10.02 |
---|---|
Spring - 컨테이너 (0) | 2024.10.02 |
Spring - Spring Framwork 구조 (1) | 2024.10.02 |
Spring - Spring Framwork 정의 (2) | 2024.10.02 |
Spring - 스프링 프레임워크 (0) | 2024.08.19 |