[Spring] Spring? Spring Boot?

    Intro

     백엔드 개발에 대해 공부를 하다 보면, 백엔드 개발을 하기 위한 언어에도 여러 가지가 존재하는 것을 알 수 있다. Java, JavaScript(node.js), Ruby, Python 등... 또한, 이러한 언어들에서 웹 개발을 조금 더 수월하게 진행하게 해주기 위한 프레임워크들(Spring, Django ..)등 많은 언어들이 있을 것이다.

     나는 Java Spring을 이용한 백엔드 개발자가 되는 것을 희망하고 있었는데, 그 이유는 단순히 "현재 기업에서 많이 선택하는 언어인 것으로 알고 있고, 입문하기에 자료들이 가장 많지 않을까?" 하는 이유였다. 그런데 조금 자세히 보면 Java? Java Spring? Spring Boot? 등 처음 입문하는 사람들은 찾아보지 않으면 그 의미를 정확히 모르고 사용할 수도 있다(지금의 나처럼..). 따라서 이번에는 Java Spring이란 무엇이고, Spring과 Spring Boot는 다른 점이 무엇인지 알아보고자 한다.


    Spring이란?

    정의

    Spring이란, JAVA 언어를 기반으로 애플리케이션 개발을 편하게 해주는 오픈소스 애플리케이션 프레임워크이다.

    정의를 쓰고 나서 보았을 때에, 프레임워크가 무엇인지? 궁금할 수 있다.

     프레임워크란, Frame(틀) + Work(일) 로 생각해볼 수 있듯이, 어떠한 일을 처리하기 위한 틀(구조) 이라고 생각하면 편하다. 애플리케이션 개발 시, 필수적인 코드, 알고리즘, DB 커넥션 등의 기능들의 틀을 제공하고, 이 틀 안에서 개발자는 원하는 방식으로 코드를 작성하여 개발을 진행할 수 있다.

    즉, Spring은 Java 언어를 이용해 웹 개발을 조금 더 쉽게 해주는 역할이라고 생각할 수 있다.

    특징

    그렇다면 Spring 프레임워크는 어떠한 특징을 가지고 있길래, 많은 개발자들이 사용하는 걸까?

    POJO(Plan Old Java Object) 방식

     POJO 방식이란, 순수 Java 언어만을 이용해서 생성한 객체를 의미한다. 그렇다면 이러한 방식이 왜 특징이 될 수 있는걸까?

     그 이유는, Java 스펙에 정의된 기술만을 이용하였다는 부분 때문이다. 만약, 어떠한 객체를 생성함에 있어서 외부 라이브러리를 import하여 의존하였다고 생각해보자. 이 때에, 외부 라이브러리가 버전 변화 등의 사유로 인해 코드가 변경되었을 경우, 변경된 기술로 만들어진 객체에 대해서, 모든 부분에서 코드가 변경되어야 한다.

     하지만 순수 Java 언어를 이용하여 객체를 생성하였다면, 보다 유연하게 외부 변화 등에 대해 대처할 수 있다. 사용자의 입장에서는, 물론 Java 버전이 달라짐에 따라서 Spring과의 호환 등에 대해서도 생각을 해야 하겠지만, 만약 하위 버전의 Java를 사용한다면 그에 호환되는 Spring 버전을 선택하게 된다면, 그 이후로는 그 버전에 맞는 Java 스펙을 통해 개발에만 집중하게 될 수 있다.

    IOC (Inversion Of Control) - 제어의 역전 

     먼저 단어만 보았을 때에 제어를 역전한다고 하는데 어떤 제어에 대한 부분인지에 대한 궁금증부터 들게 된다.

     결론부터 미리 말하자면, 객체의 생성, 메서드의 호출, 소멸 등, 객체의 생명주기에 대한 부분을 개발자가 아닌 프레임워크가 담당하게 한다는 것이다. 즉 객체를 관리하는 주체가 개발자(나)가 아닌 프레임워크가 된다. 따라서 제어권이 역전되었다고 볼 수 있다.

     우리는 Spring을 통해 개발하면서, Controller, Service, Repository 등 객체들의 동작을 직접 구현하지만, 해당 객체들을 어느 시점에서 생성하고 호출하고 소멸할지에 대해서는 정해주지 않는다.

    만약, 외부에서 가져온 코드를 작성하지만, 내가 코드의 직접적인 흐름을 제어한다면 그건 라이브러리 이다. "제어 흐름"이 누구에게 있는가가 프레임워크와 라이브러리의 큰 차이라고 볼 수 있다.

    DI (Dependency Injection) - 의존성 주입

     DI는 객체를 직접 생성하는 것이 아닌, 외부(스프링 컨테이너)에서 생성한 후에 그 객체를 가져다 사용하는 방식이다.

     외부에서 두 객체 간의 관계를 설정해주는 디자인 패턴으로, 인터페이스를 사이에 두어 클래스 레벨에서 의존관계가 고정되지 않도록 하고, 런타임 시 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 한다.

    public class Controller {
        private Service service;
        
        service.example();
    }

     만약, 위 코드와 같이 Controller 객체에서 Service 객체를 사용할 때에, Service의 example이라는 코드가 변경되면 Controller 의 기능이나 return값에 영향을 줄 수 있게 된다. 이렇게 두 객체간의 관계를 맺어주는 것을 의존성 주입이라고 하며, Spring에서는 3가지 방법의 의존성 주입이 있다.

    1. 생성자 주입 - 권장

    public class Test {
        private Example example;
    
        @Autowired
        public Test(Example example) {
            this.example = example;
        }
    }

     생성자에, @Autowired 어노테이션을 붙여 의존성을 주입받을 수 있다. 생성자 주입은, 객체 생성 시에 호출되기 때문에 Example이라는 객체가 변하지 않거나, 반드시 주입받아야 하는 경우 강제하기 위해서 사용한다.

     

    2. 필드 주입

    public class Test {
        @Autowired
        private Example example;
    }

     생성자 주입보다는 코드가 짧지만, 의존관계를 정확히 파악할 수 없다. 필드 주입 시에 final 키워드를 선언할 수 없기 때문에 Example이라는 객체가 변할 수 있다. 또한, example과 test 모두에서 동시에 의존성 주입이 발생하면 순환참조 오류가 발생할 수 있다.

    final 키워드는 선언한 이후에 변경이 불가능하기 때문에, 선언과 동시에 초기화를 해주어야 한다. 그런데 Spring 컨테이너에서 Bean(객체)를 초기화함에 있어서 오류가 발생할 수 있기 때문에 필드 주입시에는 final 키워드를 선언할 수 없다고 한다.
    public class Test {
        @Autowired
        private Example example;
    }
    
    public class Example {
        @Autowired
        private Test test;
    }

    만약, 필드 주입을 통해서 두 객체가 서로를 참조하고 있다면, Test 객체를 초기화 하려할 때 Example 객체를 주입하려고 할 텐데, Example 객체를 초기화 할 때 다시 Test 객체를 주입하려고 한다. 이러한 순환 참조 현상을 방지하기 위해서 생성자 주입이 권장된다고 한다. (생성자 주입을 하게 되면 먼저 생성된 객체부터 초기화하기 때문에 순환 참조 현상이 방지된다?)

    3.Setter(수정자) 주입

    public class Test {
        private Example example;
    
        @Autowired
        public setExample(Example example) {
            this.example = example;
        }
    }

     생성자 주입의 경우에는 객체를 생성함과 동시에 의존성을 주입하기 때문에, 필수적인 의존성들이 담기게 된다. 하지만 Setter 주입의 경우에는 객체를 생성한 이후에 의존성이 필요하다고 판단될 때에 동적으로 의존성을 주입하여 관리할 수 있는 차이점이 존재한다.

    AOP (Aspect Oriented Programming) - 관심 지향 프로그래밍

    만약 내가 카페에서 어떠한 작업을 하려고 할 때에

    public class cafe {
        
        public void 주문하기 {
            // 자리에서 일어남
            // 주문을 함
            // 자리에 앉음
        }
        
        public void 화장실가기 {
            // 자리에서 일어남
            // 화장실 다녀옴
            // 자리에 앉음
        }
        
        public void 쓰레기버리기 {
            // 자리에서 일어남
            // 쓰레기를 버림
            // 자리에 앉음
        }
        
    }

     이러한 로직을 수행한다고 하였을 때에, 3가지 로직 모두 자리에서 일어나고 앉는 부분이 공통적이며 핵심 기능보다는 부가적인 기능이라는 느낌이 강합니다. 이럴 때 핵심 로직과 부가 기능을 분리하여 애플리케이션 전체에 걸쳐 사용되는 부가 기능을 모듈화하여 재사용할 수 있도록 하는 것이 AOP 기법이다.

     AOP를 사용하게 된다면, 유지보수적인 측면에서 이점이 있고, 또한 내가 원하는 핵심 로직에 더 집중하여 개발을 진행할 수 있다는 장점이 있다.

    PSA (Portable Service Abstraction) - 일관된 서비스 추상화

     Spring으로 백엔드 개발을 하며 Database로 Mysql을 사용하고 있는데 다른 DB로 변경해야할 일이 존재할 수 있는데, 이럴 때, 모든 코드를 확인하며 수정하거나 새로운 코드로 작성을 하는 경우가 존재할 수 있다.

     Spring은 JDBC(Java DataBase Connectivity)라는 데이터베이스에 접근하는 방법은 규정한 인터페이스를 제공하기 때문에, 코드의 변경 없이 다른 DB를 사용할 수 있게 되는 것이다.

     JDBC와 같이, 특정 기술과 관련된 서비스를 추상화하여 일관된 방식으로 사용할 수 있도록 한 것을 PSA라고 한다.


    그렇다면 Spring Boot란?

     이렇게 장점이 많은 Spring에도 몇 가지 단점이 존재했는데, 바로 설정하는 것이 복잡하다는 점이었다. Spring Boot는 초기에 "Spring Boot Starter"라는 프로젝트명으로 시작되었는데, 설정과 구성을 간단하게 하여 Spring을 통한 애플리케이션 개발을 빠르게 시작할 수 있도록 도와주는 프로젝트였다. 즉, Spring을 보다 쉽게 사용할 수 있게 해주는 도구와 같은 개념이다.

     기본적으로 Spring은 개발자가 직접 설정 파일을 작성하여 스프링 컨테이너를 구축하고, 필요한 빈 객체를 등록하고, 빈 객체간의 의존성을 주입해주어야 했다. 반면, Spring Boot는 프로젝트 설정과 라이브러리 의존성을 자동으로 처리해주는 기능을 제공한다.

    특징

    • Embedded Tomcat(Spring Boot 내부에 Tomcat 포함)을 사용
      • 따로 외부 Tomcat을 사용하거나 버전 관리를 해야 하는 번거로움이 적다.
    • starter을 통한 dependency 자동화
      • 과거 Spring에서는, 각각의 dependency끼리 호환되는 버전을 일일이 설정해야 했고, 한 dependency의 버전을 변경하려면 그에 호환될 수 있도록 dependency들을 처리해야 했다. 하지만 Spring Boot는 이를 알아서 관리해준다.
    • XML 설정을 하지 않아도 된다.
      • 조사를 해보니 Spring을 사용할 때에는, POM.XML, WEB.XML 등 여러 가지 xml파일을 설정해주어야 했지만, Spring Boot는 이를 알아서 처리해준다.(물론 원한다면 설정할 수 있다)
    • 독립적으로 실행 가능한 Jar 파일로 프로젝트를 빌드할 수 있다.
      • 클라우드 서비스 및 도커와 같은 가상화 환경에 빠르게 배포할 수 있다.

     

     글을 작성하기 이전에는 Spring과 Spring Boot가 같은 것이라고 생각했다. 하지만 공부를 해 가며 Java에서 애플리케이션을 쉽게 만들기 위해 Spring이 탄생했고, 또한 이 Spring을 쉽게 사용하기 위해 Spring Boot가 생겨난 것을 보면서 신기하다는 생각 또한 하게 되었다. 그렇다면, 시간이 지나서 아예 새로운 언어가 백엔드 주요 포지션을 점거하지 않는 이상 Spring Boot를 더 쉽게 사용할 수 있게 해주는 프로젝트도 생기지 않을까 하는 궁금증 또한 생겼다.

     백엔드 및 Spring 관련 지식들을 공부하다 보면, 한 가지를 조사하면 그에 맞게 알아야 하는 수많은 지식들이 존재해서 어디까지를 선으로 그어야 하는 지 조금 어렵지만, 차근차근 정리해나가고 싶다.

    📒 작성된 내용 중에 잘못된 부분이 있다면, 언제나 지적해주시면 감사하겠습니다.


    Reference

    https://www.codestates.com/blog/content/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

     

    스프링과 스프링부트(Spring Boot)ㅣ정의, 특징, 사용 이유, 생성 방법

    스프링은 Java 백엔드 개발에 있어 떼어놓을 수 없는 프레임워크입니다. Java 백엔드의 핵심 기술이 되는 스프링 프레임워크와 스프링 부트가 무엇인지, 나아가 스프링 부트를 활용하여 프로젝트

    www.codestates.com

    https://velog.io/@alghrksl/Spring-Spring-%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80

     

    [Spring] Spring 이란 무엇인가?

    Spring 이란?JAVA의 웹 프레임워크로 JAVA 언어를 기반으로 사용한다. JAVA로 다양한 어플리케이션을 만들기 위한 프로그래밍 틀이라 할 수 있다.JAVA의 활용도가 높아지면서, JAVA를 이용한 기술이 JSP,

    velog.io

     

    https://velog.io/@ohzzi/Spring-DIIoC-IoC-DI-%EA%B7%B8%EA%B2%8C-%EB%AD%94%EB%8D%B0

     

    [Spring DI/IoC] IoC? DI? 그게 뭔데?

    스프링을 공부하다 보면 꼭 나오는 이야기가 있다. 스프링은 IoC 컨테이너로 빈을 관리한다. 스프링은 DI를 사용한다 .DI 방법에는 생성자 주입, setter 주입, 필드 주입 등이 있다.... 아니 근데 대체

    velog.io

    https://cheershennah.tistory.com/227

     

    Spring DI 스프링 의존성 주입 3가지 방법

    Spring DI 스프링에서 의존성 주입(DI)이란, 객체간 의존성을 개발자가 객체 내부에서 직접 호출(new연산자)하는 대신, 외부(스프링 컨테이너)에서 객체를 생성해서 넣어주는 방식이다. 외부에서 두

    cheershennah.tistory.com

    https://velog.io/@courage331/Spring-%EA%B3%BC-Spring-Boot-%EC%B0%A8%EC%9D%B4

     

    Spring 과 Spring Boot 차이

    스프링 프레임워크(Spring Framework)는 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 간단히 스프링(Spring)이라고도 불린다. 동적인 웹 사이트를 개발하기 위한 여러 가지 서비스를 제

    velog.io

     

    댓글