카테고리 없음

33.5일 아직무기력이지만 가보자 스프링시바거

바론고 2022. 6. 13. 20:01

Java의 기본 문법만으로 어떠한 소프트웨어를 만들 수 있을까요?

아마도 콘솔 출력 프로그램 

Java의 GUI API인 AWT나 Swing을 사용한 데스크탑 애플리케이션 정도

 

 

하지만 여러분들이 앞으로 만들어야하는 소프트웨어는 서버에서 동작하는 Java 기반의 웹 애플리케이션입니다.

Java 기반의 웹 애플리케이션을 만드는 다양한 기술들이 존재하는데, 그 중에서 여러분들이 앞으로 배워야 할 기술은 바로 Spring Framework이라는 오픈소스 기반의 기술입니다.

 

‘이 개념은 도저히 이해가 되지 않아’

 

하지만 단계적으로 천천히 그리고 포기하지 말고 꾸준히

이번 유닛에서는 Spring Framework이 무엇인지, Spring Framework을 왜 배워야 하는지 등 Spring Framework의 기본 개념을 알아보면서 Spring Framework과 친해지는 시간을 가져보도록 하겠습니다.

Spring Framework을 여러분들 것으로 만들기 위해 마지막까지 시바거!

 

 

Framework이란?

 

HTML 5 버전에서는 지원하고 있지 않지만 웹의 초창기 시절에는 HTML 문서를 구성하는 태그 중에서 frame이라는 태그가 존재했습니다.

<frameset cols="33%,*,33%">
    <frame name="left" src="/left_menu"/>
    <frame name="center" src="/context"/>
    <frame name="right" src="/right_menu"/>
</frameset>
[코드 2-1] HTML의 frame 태그의 예

코드 2-1은 웹의 초창기 시절 사용하던 frame 태그의 사용 예시입니다. 보시는 것처럼 frameset과 frame 태그를 이용해서 HTML 문서의 만 구성하고 있는 것을 볼 수 있습니다. 그리고 예제 코드에는 나와 있지 않지만 HTML 문서의 세부 내용들은 별도의 html 파일에 구성이 되어 있습니다.

그렇다면 이번에는 frame과 유사한 의미를 가지는 Framework의 예를 들어보겠습니다.

여러분들이 이미 배웠던 Java에서 Framework의 의미를 찾아볼 수 있는데, 그것은 바로 Collections Framework입니다.

여러분들이 이미 알고 계시다시피 Java에서 자주 사용하는 Map이나 Set, List 등의 Collection들은 데이터를 저장하기 위해 널리 알려져 있는 자료구조를 바탕으로 비슷한 유형의 데이터들을 가공 및 처리하기 쉽도록 표준화 된 방법을 제공하는 클래스의 집합입니다.

그런데 왜 하필 Java의 Collection에 Framework이라는 용어를 붙였을까요?

여러분들은 ‘틀’이나 ‘뼈대’ 같은 단어를 듣게 되었을 때, Java 언어의 구성요소 중에서 어떤 것이 제일 먼저 떠오르나요?

Java 클래스의 유형 중에서 기본적인 뼈대로만 구성되어 있는 것은 바로 추상 메서드만 정의되어 있는 인터페이스(Interface)입니다. 그리고 Java에서의 Collection은 바로 Map, Set, List 같은 인터페이스와 그 인터페이스들을 구현한 구현체들의 집합인 것입니다.

결론적으로 프로그래밍 상에서의 Framework은 기본적으로 프로그래밍을 하기 위한 어떠한 틀이나 구조를 제공한다라는 것을 알 수 있습니다.

그리고 Framework은 프로그래밍을 위한 기본 구조를 제공하는 것 이상의 많은 기능들을 제공합니다.

개발하고자 하는 애플리케이션을 그 밑바닥부터 일일이 전부 개발하는 것이 아니라 서로 다른 애플리케이션 간의 통신이나, 데이터를 데이터 저장소에 저장하는 등의 다양한 기능들 역시 Framework이 라이브러리 형태로 제공함으로써 개발자가 애플리케이션의 핵심 로직을 개발하는 것에 집중할 수 있도록 해줍니다.

Framework과 Library의 차이는?

많은 분들이 Framework을 Library와 같은 의미라고 오해하기도 하는데, 그 의미가 헷갈리는 것은 프로그래밍 입문자들에게는 어찌보면 자연스러운 일이라고 생각합니다.

애플리케이션의 구현을 위해 필요한 여러가지 기능들을 제공한다라는 의미에서 Framework과 Library는 유사하다고 볼 수 있지만 Framework과 Library에는 결정적인 차이점이 존재하는데 그것은 바로 애플리케이션에 대한 제어권입니다.

@SpringBootApplication
@RestController
@RequestMapping(path = "/v1/message")
public class SampleApplication {
    @GetMapping
    public String getMessage() {  // (2)
        String message = "hello world";
        return StringUtils.upperCase(message); // (1)
    }

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}

[코드 2-2] Framework과 Library의 차이점을 이해하기 위한 예시 코드

코드 2-2는 Java 웹 애플리케이션을 개발하기 위해 우리가 앞으로 배우게 될 Spring Framework 코드 중 일부입니다.

무언가 복잡해 보이지만 Spring Framework에 대한 문법 자체는 몰라도 됩니다.

아니, 모르는것이 좋습니다.

코드 2-2에서 우리가 알아야하는 것은 Spring Framework에서 사용하는 코드를 통해 Framework과 Library의 차이점이 무엇인지 이해하는 것, 그것 한가지라는 사실만 기억하면서 가볍게 읽어보면 되겠습니다.

먼저 코드 2-2에서 명확하게 Library를 사용하는 부분은 (1)의 ‘StringUtils.upperCase(message)’ 입니다.

StringUtils 클래스는 Apache Commons Lang3 라이브러리의 유틸리티 클래스 중 하나인데 애플리케이션이 동작하는 중에 이 StringUtils 클래스의 upperCase() 메서드의 파라미터로 전달하는 문자열(message 변수)을 대문자로 변환하고 있습니다.

그렇다면 StringUtils 클래스가 라이브러리라는 것을 어떻게 판단할 수 있을까요?

코드 2-2와 같이 애플리케이션 코드는 애플리케이션을 개발하는 사람 즉, 개발자가 작성을 할 것입니다. 이렇게 개발자가 짜 놓은 코드내에서 필요한 기능이 있으면 해당 라이브러리를 호출해서 사용하는 것이 바로 Library입니다.

즉, 애플리케이션 흐름의 주도권이 개발자에게 있는 것입니다.

그렇다면 Framework은 어떨까요?

코드 2-2에서 사용한 애너테이션이나 main() 메서드 내의 SpringApplication.run() 메서드는 Spring Framework에서 지원하는 기능들인데 이러한 기능들은 라이브러리와는 다르게 코드 상에는 보이지 않는 상당히 많은 일들을 합니다.

(2)의 getMessage() 메서드 내부의 코드처럼 개발자가 메서드내에 코드를 작성해두면, Spring Framework에서 개발자가 작성한 코드를 사용해서 애플리케이션의 흐름을 만들어냅니다.

즉, 애플리케이션 흐름의 주도권이 개발자가 아닌 Framework에 있는 것입니다.

짧은 내용이긴하지만 Framework과 Library의 차이점을 학습하면서 여러분은 Spring Framework의 핵심 개념인 IoC(Inversion Of Control, 제어의 역전)라는 중요한 개념을 알게된 것입니다.

지금 당장 Framework과 Library의 차이점이 명확하게 이해되지 않아도 실망할 필요는 없습니다.

여러분들이 Spring Framework의 개념에 익숙해진 후에, 다시 한번 이 챕터의 내용을 확인하신다면 ‘아, 이게 바로 그 의미구나! 별거 아니네?’ 라는 생각을 할거라 확신합니다.

그때까지 저희와 함께 마지막까지 열심히 달려봅시다!


핵심 포인트

  • 프로그래밍 상에서의 Framework은 기본적으로 프로그래밍을 하기 위한 어떠한 틀이나 구조를 제공한다.
  • Framework은 개발자가 애플리케이션의 핵심 로직을 개발하는 것에 집중할 수 있도록 해준다.
  • Library는 애플리케이션 흐름의 주도권이 개발자에게 있는 반면, Framework은 애플리케이션 흐름의 주도권이 개발자가 아닌 Framework에 있다.

 

 

Spring Framework이란?

2004년 버전 1.0이 처음 릴리즈 된 이후로 사실상 Java 기반의 웹 애플리케이션을 개발하는데 있어 표준이라고 해도 과언이 아닐만큼의 대세가 되었습니다.

 

다만 지금은 Spring Framework을 학습함으로 인해서 객체 지향 설계 원칙에 잘 맞는 재사용과 확장이 가능한 애플리케이션 개발 스킬을 향상시킬 수 있다는 것, 그리고 보다 나은 성능과 서비스의 안전성이 필요한 복잡한 기업용 엔터프라이즈 시스템을 제대로 구축하기 위한 능력을 기를 수 있다라는 사실만 기억해두시길 바랍니다.

Spring Framework을 배워야 하는 이유

지금부터 Spring을 본격적으로 도입하기 전의 기술들을 단계적으로 살펴볼까요?

JSP를 이용한 애플리케이션

JSP는 Java Server Page의 약자로 초창기 Java 기반의 웹 애플리케이션 개발은 JSP를 통해 이루어졌습니다.

JSP 개발 방식은 사용자에게 보여지는 View 페이지쪽 코드와 사용자의 요청을 처리하는 서버쪽 코드섞여있는 형태의 개발 방식입니다. 쉽게 말하자면 웹 브라우저를 통해서 사용자에게 보여지는 클라이언트 측 html/Javascript 코드와 사용자의 요청을 처리하는 서버 측 Java 코드가 뒤섞여 있는 방식입니다.

JSP 방식이 어떤 형태인지는 예제 코드를 직접 보면 이해가 쉬울 것 같습니다.

  • JSP 방식 예제 코드
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    <!-- (1) 시작 -->
    <%
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
    
        System.out.println("Hello Servlet doPost!");
    
        String todoName = request.getParameter("todoName");
        String todoDate = request.getParameter("todoDate");
    
        ToDo.todoList.add(new ToDo(todoName, todoDate));
    
        RequestDispatcher dispatcher = request.getRequestDispatcher("/todo_model1.jsp");
        request.setAttribute("todoList", ToDo.todoList);
    
        dispatcher.forward(request, response);
    %>
    <!-- (1) 끝 -->
    <html>
    <head>
        <meta http-equiv="Content-Language" content="ko"/>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    
        <title>TODO 등록</title>
        <style>
            #todoList {
                border: 1px solid #8F8F8F;
                width: 500px;
                border-collapse: collapse;
            }
    
            th, td {
                padding: 5px;
                border: 1px solid #8F8F8F;
            }
        </style>
        <script>
            function registerTodo(){
                var todoName = document.getElementById("todoName").value;
                var todoDate = document.getElementById("todoDate").value;
    
                if(!todoName){
                    alert("할일을 입력해주세요..");
                    return false;
                }
                if(!todoDate){
                    alert("날짜를 입력해주세요.");
                    return false;
                }
    
                var form = document.getElementById("todoForm");
                form.submit();
    
            }
        </script>
    </head>
    <body>
        <h3>TO DO 등록</h3>
        <div>
            <form id="todoForm" method="POST" action="/todo_model1.jsp">
                <input type="text" name="todoName" id="todoName" value=""/>
                <input type="date" name="todoDate" id="todoDate" value=""/>
                <input type="button" id="btnReg" value="등록" onclick="registerTodo()"/>
            </form>
        </div>
        <div>
            <h4>TO DO List</h4>
            <table id="todoList">
                <thead>
                    <tr>
                        <td align="center">todo name</td><td align="center">todo date</td>
                    </tr>
                </thead>
    						<!-- (2) 시작 --->
                <tbody>
                    <c:choose>
                        <c:when test="${fn:length(todoList) == 0}">
                            <tr>
                                <td align="center" colspan="2">할 일이 없습니다.</td>
                            </tr>
                        </c:when>
                        <c:otherwise>
                            <c:forEach items="${todoList}" var="todo">
                                <tr>
                                    <td>${todo.todoName}</td><td align="center">${todo.todoDate}</td>
                                </tr>
                            </c:forEach>
                        </c:otherwise>
                    </c:choose>
                </tbody>
    						<!-- (2) 끝 -->
            </table>
        </div>
    </body>
    </html>
    [코드 2-3] JSP 방식의 예제 코드

 

코드 2-3은 JSP 방식의 예제 코드입니다.

위 코드는 사용자가 자신의 할일을 등록하는 화면과 등록한 할일을 목록으로 보여주는 화면을 포함한 아주 간단한 로직입니다.

여러분들이 JSP 방식의 구체적인 구현 방법은 알 필요가 없기 때문에 코드의 대략적인 구조만 설명하고 이 방식의 문제점을 살펴보겠습니다.

먼저 코드 상단의 (1) 영역은 클라이언트의 요청을 처리하는 서버쪽 코드입니다. 익숙한 Java의 코드가 눈에 들어오시나요?

다음으로 코드 아래 쪽의 (2) 영역은 서버로부터 전달 받은 응답을 화면에 표시하기 위한 JSP에서 지원하는 jstl 태그 영역입니다.

마지막으로 (1), (2)의 영역이외의 나머지 구현 코드들은 사용자에게 보여지는 화면을 구성하는 html 태그 및 css 스타일 코드와 할일 등록 시 유효성 검사를 실시하는 Javascript 코드 즉, 클라이언트 측에서 사용하는 기술들에 해당하는 코드입니다.

기술의 구현 방법을 잘 모르긴해도 코드 자체가 너무 길어서 가독성도 떨어지고, 너무 복잡해 보인다는 생각이 들지 않나요?

실제로 이 방식은 애플리케이션의 유지 보수 측면에서 최악의 방식이라고 볼 수 있습니다. 웹 디자이너와 html 퍼블리셔 그리고 자바스크립트 개발자 및 자바 개발자 간에 효율적으로 협업하는 것이 거의 불가능한 수준이기도 하구요.

실제로 JSP 방식으로 개발 할 때에는 프런트엔드/백엔드 영역을 구분하지 않고 양쪽을 모두 개발하는 개발자들이 많았습니다. 코드 2-3처럼 프런트엔드 영역과 백엔드 영역의 코드가 뒤섞여있다보니 어찌보면 당연한 결과라고 볼 수 있겠습니다.

여러분들이 JSP 방식을 사용하는 시대에 개발자로 입문하지 않는다는 것이 너무너무 다행이라는 생각까지 드는군요. ^^

그러면 이번에는 JSP 방식 보다는 조금 나은 개발 방식인 서블릿(Servlet)을 이용한 개발 방식을 살펴 보도록 하겠습니다.

서블릿(Servlet)을 이용한 애플리케이션

앞에서 설명한 JSP 방식 역시 내부적으로는 Servlet 방식을 사용합니다. Servlet은 클라이언트 웹 요청 처리에 특화된 Java 클래스의 일종이라고 보시면 되는데, Spring을 사용한 웹 요청을 처리할때에도 내부적으로는 Servlet을 사용한다라는 사실은 기억해두시면 좋을 것 같습니다.

여기서 의미하는 Servlet을 이용한다라는 의미는 Servlet을 위한 Java 코드가 클라이언트 측 코드에서 분리되어 별도의 Java 클래스로 관리된다는 것을 의미합니다.

코드를 보면 쉽게 이해가 되실테니 역시 예제 코드를 통해 이 방식을 이해해 보도록 하겠습니다.

 

 

뭔가 아주 많은 일을 할 것 같지만 데이터를 가공하는 비즈니스 로직이 있는 것도 아니고, 가공된 데이터를 데이터베이스에 저장하는 등의 데이터 액세스 로직 역시 존재하지 않는데도 불구하고 코드 자체가 너무 길어보입니다.

그렇다면 Spring에서는 이러한 서블릿 클래스의 코드들이 어떤식으로 개선되는지 보도록하겠습니다.

Spring MVC를 이용한 애플리케이션

 

서블릿 방식의 코드에서는 클라이언트의 요청에 담긴 데이터를 꺼내오는 작업을 개발자가 직접 코드로 작성 해야되고, 캐릭터셋도 지정 해주어야 하는데 반면에 Spring MVC 방식의 코드에서는 눈에 보이지 않지만 그런 작업들을 Spring에서 알아서 처리해줍니다.

그런데 Spring의 이런 편리함과 간결함에도 불구하고 Spring 기반의 애플리케이션의 기본 구조를 잡는 설정 작업이 여전히 불편하다는 단점이 존재했었습니다.

실제로 Spring MVC의 이런 복잡한 설정때문에 Spring 학습을 포기하는 입문자들도 많이 있었고, Spring의 핵심 원리를 학습하고, 이해하기도 모자란 시간에 Spring의 설정 문제로 애플리케이션을 띄워보지도 못한채 며칠을 끙끙 앓는 그런 상황들이 많았던게 사실입니다.

이러한 Spring 설정 상의 문제가 개선이 되지 않았다면 여러분들이 Spring에 익숙해지는 시간은 그만큼 더 길어졌을거라고 생각합니다.

다행히 이러한 문제가 대부분 개선된 Spring Boot이 탄생하게 됩니다.

Spring Boot을 이용한 애플리케이션

  •  [코드 2-7] Spring Boot 기반의 예제 코드
  • @RestController public class TodoController { private TodoRepository todoRepository; @Autowired TodoController(TodoRepository todoRepository) { this.todoRepository = todoRepository; } @PostMapping(value = "/todo/register") @ResponseBody public Todo register(Todo todo){ // (1) todoRepository.save(todo); // (2) return todo; } @GetMapping(value = "/todo/list") @ResponseBody public List<Todo> getTodoList(){ return todoRepository.findAll(); // (3) } }

 

코드 2-7은 Spring MVC 기반의 코드를 Spring Boot 기반에서 조금 더 개선한 모습입니다.

이번에는 클라이언트 측에서 전달한 요청 데이터를 (1)과 같이 Todo라는 클래스에 담아서 한번에 전달 받을 수 있도록 했습니다. 요청 데이터가 Todo 객체로 변경되는 것은 Spring이 알아서 해줍니다.

그리고 이 전 방식까지는 클라이언트가 전달한 요청 데이터를 테스트 목적으로 단순히 List에 담았는데 이번에는 (2), (3)과 같이 데이터베이스에 저장해서 데이터 액세스 처리까지 하도록 했습니다.

이렇게 데이터를 실제로 저장하는 기능을 추가했는데도 불구하고 코드의 길이는 크게 바뀐 것이 없고, 오히려 더 깔끔해지기까지 했습니다.

[코드 2-6]과 같은 Spring MVC 방식에서의 복잡한 설정 파일은 어떻게 되었을까요?

1
2
3
4
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

[코드 2-8] Spring Boot의 구성 파일

코드 2-8은 Spring Boot에서의 구성(설정) 파일입니다.

조금 허탈할지도 모르지만 Spring Boot을 사용하지 않는 Spring MVC 방식에서 겪어야 했던 설정의 복잡함을 Spring Boot에서는 찾아볼 수 없습니다. 심지어 데이터베이스를 연동하지 않았다면 [코드 2-8]에 입력한 4줄의 코드도 필요하지 않습니다.

그 많던 설정 파일의 내용들은 어디에 갔을까요?

이제는 Spring의 복잡한 설정 작업마저도 Spring이 대신 처리를 해주기때문에 개발자는 애플리케이션의 핵심 비즈니스 로직에만 집중할 수 있게되었습니다.

이제는 Spring Framework을 왜 배워야 하는지 어느 정도 이해 했을거라고 생각합니다.

물론 입문자들이 처음부터 Spring의 핵심 개념들을 쉽게 이해 생각할거라고 생각하지는 않습니다.

하지만 아무것도 모르고 머리속이 텅빈 상태로 세상에 태어나서 언어에 대한 지식을 스펀지처럼 흡수하는 아기들처럼 개발 지식과 경험이 오히려 거의 없는 입문자들이 개발 경험이 많은 경력자들 보다 Spring을 학습하는 속도가 더 빠를수도 있다고 생각합니다.

어려움이 있을 수 있겠지만 Spring은 정말 재미있고, 객체 지향의 설계 원칙을 잘 따르는 놀라운 기술이기도 합니다.

Spring을 여러분들의 것으로 만들기 위해 마지막까지 포기하지 않고 저희와 함께 하기를 바랍니다.


핵심 포인트

  • Spring Framework이 도입되기 전에는 JSP나 Servlet 기술을 사용한 Model1, Model2 아키텍쳐를 기반으로 한 Java 웹 애플리케이션을 제작하였다.
  • Spring MVC 방식이 도입됨으로써 Java 웹 애플리케이션의 제작 방식이 획기적으로 변하게 되었다.
  • Spring MVC 설정의 복잡함과 어려움을 극복하기 위해 Spring Boot이 탄생하게 되었다.

심화 학습

  • Java 서블릿(Servlet)이란?
    • Java Servlet 자체를 사용하는 기술은 현재 거의 사용하고 있지 않지만 Servlet은 Spring MVC 같은 Java 기반의 웹 애플리케이션 내부에서 여전히 사용이 되고 있습니다.
    •  
  • 서블릿 컨테이너(Servlet Container)란?
    • 서블릿 컨테이너(Servlet Container)는 서블릿(Servlet) 기반의 웹 애플리케이션을 실행해주는 것부터 시작해서 Servlet의 생명 주기를 관리하며, 쓰레드 풀(Thread Pool)을 생성해서 Servlet과 Thread를 매핑 시켜주기도 합니다.
    •  
    • 아파치 톰캣(Apache Tomcat)은 서블릿 컨테이너의 한 종류로써 Spring MVC 기반의 웹 애플리케이션 역시 기본적으로 아파치 톰캣에서 실행이 됩니다.