티스토리 뷰

728x90
반응형

 

Spring Framework, 혹은 Spring은 Java/Kotlin을 기반으로 한 오픈소스 웹 프레임워크이다.

 

특히나 엔터프라이즈급 애플리케이션 개발에 필요한 기능이 종합적으로 포함되어 있는데,

 

대한민국 전자정부 표준프레임워크의 기반 기술로도 쓰이도 있다.

 

  • 엔터프라이즈급 애플리케이션 - 기업을 대상으로 하는, 대규모 데이터와 트랜잭션 처리가 이루어지는 앱
  • Framework(프레임워크)

    • 특정 목적을 위해 설계된 구조 혹은 뼈대
    • 소프트웨어의 설계와 구현을 위해 재사용이 가능한 일련의 클래스와 라이브러리를 제공하는 것
    • 앱 개발을 위한 기초 프로그램이자 반제품
    • Framework = Design Pattern(재사용 가능한 솔루션) + Library, 즉 라이브러리를 포함한 개념
  • Library와 Framework의 차이

    • Library는 사용자가 호출해 사용한다. 앱 실행 흐름의 주도권이 개발자에게 있다.
      재사용이 가능한 클래스와 메서드로 이루어져 있다.
    • Framework는 앱 실행 흐름의 제어가 Framework에게 있으며, 이를 IoC(Inversion of Control)라 한다.
      또한 재사용 가능한 클래스와 라이브러리를 융합해 처음부터 제공해 주는데,
      이 덕분에 개발자는 핵심 로직 개발에 집중할 수 있다.

스프링이 도입되기 전에는 JSP나 Servlet을 이용한 Moder1, Model2 아키텍처로 개발이 이루어졌다.

 

이 시기엔 프론트엔드와 백엔드 개발자의 구분이 많이 없었는데, 그 이유는 코드를 보면 알 수 있다.

<%@ 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" %>
<%
    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);
%>
<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>
            <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>
        </table>
    </div>
</body>
</html>

위 코드는 JSP방식으로 쓰인 todoList작성 프로그램이다.

 

자바에서 시작해 JSP에서 지원하는 jstl, 자바스크립트까지 코드가 혼재해 있다.

 

때문에 별 기능도 없으면서 코드가 늘어지고, 당연히 유지보수 하기에 안 좋은 형태가 되어버린다.

 

이를 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)
    }
}
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

첫 코드에서 자바 부분만 분리해 정리한 모습이다. 아래쪽에 위치한 구성(설정) 파일도 간결함을 볼 수 있다.

 

거기다 첫 코드에는 없었던 데이터베이스 저장후 데이터 액세스 처리 기능까지 넣었다.

 

스프링은 이처럼 프론트엔드와 백엔드를 분리해 개발의 생산성을 높이고, 유지보수에 최적화된 간략한 코드를 지원한다.

 

이 외에도 스프링은 크게 네 가지 특징을 가지고 있는데, 난해한 개념이지만 하나씩 살펴보자.

 

1. POJO(Plain Old Java Object)

 

위에 첨부한 그림은 스프링 삼각형(Spring Triangle)이라는 도표로서 스프링의 특징을 한눈에 담고 있다.

 

그림을 보면 POJO가 나머지 세 개념(IoC/DI, AOP, PSA)에게 둘러싸여 있는 것을 볼 수 있는데,

 

이는 나머지 세 개념을 통해 POJO를 달성할 수 있다는 것을 의미하며

 

그만큼 POJO가 중요한 개념이라는 것또한 의미한다.

 

POJO는 있는 그대로 해석하면 오래된 방식의 간단한(순수한) 자바 오브젝트라는 뜻이 되며, 

 

마틴 파울러에 의해 2000년부터 불리기 시작했다.

 

"We wondered why people were so against using regular objects in their systems and concluded that it was because simple objects lacked a fancy name. So we gave them one, and it's caught on very nicely."

"우리는 사람들이 자기네 시스템에 보통의 객체를 사용하는 것을 왜 그렇게 반대하는지 궁금하였는데, 간단한 객체는 폼 나는 명칭이 없기 때문에 그랬던 것이라고 결론지었지. 그래서 적당한 이름을 하나 만들어 붙였더니, 아 글쎄, 다들 좋아하더라고."

 

당시엔 Java EE와 같은 중량 프레임워크를 사용하며 그 프레임워크에 종속된 무거운 객체를 만드는 방식이 만연했는데,

 

POJO는 바로 이 흐름에 반발하여 나온, 순수한 Java 객체를 가리키는 단어인 것이다.

 

POJO의 특징은 아래와 같다.

 

  • 특정 기능, 규약, 프레임워크, 환경에 종속적이지 않다 - 특정 클래스, 인터페이스, 어노테이션을 상속받지(포함하지) 않는다.
  • 특정 인터페이스를 직접 구현하거나 상속받을 필요가 없어 기존 라이브러리를 지원하기가 용이하고, 객체가 가볍다(코드가 깔끔하다).
  • 객체지향 설계 원칙을 충실히 따른다.
  • 잘 만들어진 POJO 앱은 테스트와 리팩토링이 편리하다.

추가로 객체지향 설계의 5가지 원칙은 SOLID라 불리는데, 아주 간략히 보면 아래와 같다.

 

  • SRP(Single Responsibility Principle, 단일 책임 원칙)
    객체는 오직 하나의 책임을 가진다. 이는 객체의 변경 이유가 한 가지 여야 함을 뜻한다. 변경 시 목적에 따라 대상이 명확해진다.
  • OCP(Open-Closed Principle, 개방-폐쇄 원칙)
    객체는 확장에 대해서는 개방적이고 수정에 대해서는 폐쇄적이어야 한다.
    조금 더 구체적으로는 기존 코드의 수정 없이 새로운 동작을 추가하거나 변경이 가능해야 한다.
  • LSP(Liskov Substitution Principle, 리스코프 치환 원칙) - 자식 클래스는 언제나 부모 클래스를 대체할 수 있다.
  • ISP(Interface Segregation Principle, 인터페이스 분리 원칙)
    클라이언트의 목적과 용도에 적합한 인터페이스만을 제공한다. 따라서 인터페이스를 다시 작게 나눈다.
  • DIP(Dependency Inversion Principle, 의존성 역전 원칙)
    추상성이 높고 안정적인 고수준의 클래스는 구체적이고 불안정한 저수준의 클래스에 의존해서는 안 된다.
    한마디로 추상화에 의존하되 구체화에 의존하지 않는 것이다.

 

2.IoC(Inversion of Control) / DI(Dependency Injection)

 

직역하면 제어역전/의존성 주입이 된다. IoC는 위 글에서 Library와 Framework의 차이에 대해 알아볼 때 한 번 등장했었다.

 

전통적인 프로그램의 경우 개발자의 코드가 외부 라이브러리의 코드를 호출해서 이용한다.

 

Framework의 경우엔 반대로 외부 Framework가 개발자의 코드를 호출한다. 제어권이 Framework에게 있다는 뜻이다.

 

여기서 제어란 자바 객체의 생성부터 삭제까지의 라이프 사이클에 대한 제어도 포함하는데,

 

스프링이 관리하는 객체를 빈(Bean)이라고 한다.

 

IoC는 DI에 의해 구현되는데, DI는 객체간의 의존관계가 소스코드 외부에서 설정에 의해 정해지는 방식을 뜻한다.

 

객체 지향 프로그램에서 의존이란 한 객체가 다른 객체의 메서드를 호출하는 식으로 클래스의 기능을 사용하는 것이다.

 

기존에는 클래스 내부에서 객체를 만들어 사용했다면, 스프링에서는 빈을 생성한 후 필요한 곳에 주입한다.

 

혹은, 객체 간의 의존관계를 빈 설정 정보를 바탕으로 스프링이 자동으로 연결해 주는 거라고 이해해도 된다.

 

의존성 주입은 예를 들면 다음과 같이 이루어진다.

 

위와 같은 의존관계(A가 new를 통해 B에 의존)가 있다고 하자(이런 경우를 강한 결합 - Tight Coupling이라 한다).

 

MenuController 클래스는 MenuService의 객체를 생성한 후, getMenuList() 메서드를 호출하고 있다.

 

외부의 CafeClient 클래스를 만들고 객체를 생성, MenuController 클래스의 생성자 파라미터로 menuService를 전달한다.

 

이처럼 생성자를 통해서 어떤 클래스의 객체를 전달받는 것을 의존성 주입이라고 부른다.

 

의존성 주입에는 위에서 알아본 생성자를 이용한 것 말고도 세 가지 방법이 더 존재하는데,

 

생성자를 통한 의존성 주입이 권장되고 있다.

 

그렇다면 굳이 이렇게 한 단계를 더 거치면서까지 의존성 주입을 하는 이유는 무엇일까?

 

크게 다음과 같은 것이 있다.

 

  • 코드의 재사용성을 높여 준다.
  • 객체간의 결합도를 낮출 수 있다. = 의존도를 낮출 수 있다(강한 결합 Tight Coupling -> 느슨한 결합 Loose Coupling).
    이는 유연한 코드를 작성할 수 있게 한다. 강한 결합에선 하나의 객체를 변경하면 많은 객체를 수정해야 하기 때문이다.
  • 테스트가 편하다

 

3. AOP(Aspect Oriented Programming)

 

AOP(관심 지향 프로그래밍)는 OOP(Object Oriented Programming)를 구현하는 방식으로,

 

관심사(기능)의 분리를 통해 문제를 해결하는 패러다임이다.

 

구체적으로는 공통 관심사항(Cross-Cutting Concern, Aspect, 부가 기능이라고도 불림)과 핵심 관심사항(기능)을 분리해

 

각각을 모듈화*, 재사용성을 높이고 비즈니스 로직을 포함한 핵심 기능 개발에 집중하는 패러다임이라고 볼 수 있다.

 

*모듈화 - 앱의 기능을 독립적인 부품으로 분리하는 것

 

여기서 공통 관심사항이란 그림에서도 보듯이 로깅, 보안, 트랜잭션 등 앱 전반에 공통으로 사용되는 기능을 말한다.

 

즉, 필수적이지만 어쩔수 없이 반복되어야 하는 코드들을 리팩터링 해주는 것이다.

 

트랜잭션에 대해서는 이전 글에서 다룬 적이 있으니 생략한다.

 

https://gnidinger.tistory.com/444

 

[데이터베이스]SQL

SQL(Structured Query Language - 구조화된 쿼리 언어)은 데이터베이스용 프로그램 언어이다. 에스큐엘 혹은 시퀄이라고 읽으며, 데이터베이스 시스템에서 자료를 처리하는 용도로 사용된다. 이름에서

gnidinger.tistory.com

다른 개념들과 마찬가지로 AOP에는 장점이 있는데, 아래와 같다.

 

  • 코드의 간결성 및 재사용성을 높여준다.
  • 객체 지향 설계 원칙에 맞는 코드를 구현한다.

 

4. PSA(Portable Service Abstraction)

 

PSA는 서비스 기능에 접근하는 방식을 일관되게 유지하면서 기술을 유연하게 사용할 수 있도록 하는 것이다.

 

조금 더 구체적으로 보자면 서비스 추상화(Servise Abstraction)는 아래와 같은 의미를 가지며,

 

  • 같은 기능을 하는 다수의 기술을 공통의 인터페이스로 제어할 수 있게 만든 것
  • 특정 기술을 내부에 숨기고 개발자에게 편의성을 제공해주는 것

 서비스 추상화로 제공되는 기술을 다른 기술 스택으로 간단하게 바꿀 수 있는 확장성을 갖고 있는 것이 PSA이다.

 

이는 POJO원칙을 철저히 따른 스프링의 기능으로, 스프링에서 동작하는 라이브러리는

 

POJO원칙을 지키게끔 PSA(일관된 서비스 추상화)형식으로 추상화가 되어있음을 의미한다.

 

쉽게 표현하자면 잘 만든 인터페이스라고 말할 수 있다.

 

잘 만들어진 PSA 구조에서 클라이언트는 상위 클래스를 일관되게 바라보며 하위 클래스의 기능을 사용한다.

 

PSA가 요구되는 이유는 일관된 접근방식을 가져 앱의 요구사항 변경에 따른 코드 수정을 최소화하기 때문이며,

 

스프링에서 PSA가 적용되는 분야는 트랜잭션 서비스, 메일 서비스, 스프링 데이터 서비스 등이 있다.

 

마지막으로 스프링은 기능에 따라 20여가지의 모듈로 이루어져 있는데, 그 대략적인 구조는 아래와 같다.

 

출처: https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html

 

2. Introduction to Spring Framework

Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure so you can focus on your application. Spring enables you to build applications from "plain old Java o

docs.spring.io

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함