[위클리 페이퍼] 스프링 프레임워크와 일반 자바 라이브러리
2025. 4. 27. 15:24

이번주 위클리 페이퍼의 주제는

Spring Framework가 탄생하게 된 배경과 이를 통해 해결하고자 했던 문제점에 대해 설명해보자
프레임워크와 라이브러리의 차이점을 제어 흐름의 주체와 사용 방식을 중심으로 설명하고,
Spring Framework와 일반 Java 라이브러리를 예시로 들어 설명해보자

 

Spring Framework의 탄생 배경

~웹 등장 초기~

www가 등장하고 초기에는 정적인 HTML로 웹페이지가 구성됐지만 사용자의 요청에 대한 반응을 보여주는 동적인 콘텐츠의 필요성이 증가했다. 때문에 동적 웹페이지를 위한 CGI(Common Gateway Interface)프로그래밍이 등장했다.

하지만 CGI프로그래밍은 언어와 플랫폼에 독립적이라는 장점이 있지만 멀티 스레드를 지원하지 않아서 매 HTTP 요청마다 별도의 프로세스를 만들어야 했기 때문에 느리고 메모리도 많이 필요로 한다는 단점이 있었다.

이때 Java가 등장했고 CGI 대신 멀티 스레드를 지원하는 Java의 Servlet을 사용하게 된다.

 

~서블릿의 한계와 JSP~

하지만 Servlet은 자바 코드 안에 HTML코드를 작성하는 방식으로, 로직들이 혼합되어 있어 작성하기도 관리하기 어려웠다고 한다.

또한 모든 HTTP 응답/요청을 서블릿 코드 안에서 작성해야 했기 때문에 테스트도 까다로웠다고 한다.

그래서 반대로 HTML코드에 자바 코드를 삽입할 수 있게 하는 JSP가 등장했다.

하지만 JSP도 복잡한 비즈니스 로직을 작성할 때는 유지보수가 어려웠고, 큰 프로젝트에선 JSP만으로는 구조 분리가 안 됐다.

 

~드디어 EJB~

EJB( Enterprise JavaBeans )은 Java EE( Java Enterprise Edition )(과거 J2EE) 의 핵심 컴포넌트 기술 중 하나다.

(Java EE란?)

Java로 대규모 웹/서버/기업 시스템을 만들드는 데에 필요한 스펙들의 모음이다.

개발자들이 트랜잭션, 보안, 분산 시스템 등의 기능을 쉽게 사용할 수 있도록 해준다.

여기서 트랜잭션, 보안, 비즈니스 로직을 관리하는 데에 도움을 주는 기술로 EJB, HTTP 요청/응답 처리 등의 웹 기술로 JSP등이 있다.

 

EJB는 컨테이너가 트랜잭션, 보안, 스레드 등의 관리는 자동으로 해주고 개발자는 비즈니스 로직에 집중하라는 목적을 가지고 있었다. 

 

~EJB의 단점~

하지만 컨테이너가 관리를 자동으로 해준다는 목적과 달리 EJB 객체를 만들기 위해선 복잡한 인터페이스를 작성해야 했고 XML도 작성해야 했다. 이 XML은 구성 오류가 자주 발생했다.

또한 특정 WAS에 의존적인 모습을 보였다. WebSphere, WebLogic 같은 무거운 애플리케이션 서버를 필요로 했다. 이는 다양한 환경에서의 재사용성을 제한하는 주요한 원인이 됐다.

또한 의존성 없이 클래스 내부에서 다른 객체를 생성하여 결합도를 높이는 등 객체지향의 원칙에 어긋나는 부분도 많았다.

결국 EJB의 다양한 기능을 사용하기 위해 EJB 컨테이너를 설정하는 데에 걸리는 시간이 비즈니스 로직을 작성하는 시간보다 길어지게 됐다. 

 

~Spring Framework의 등장~

2002년 로드존슨( Rod Johnson )은 자신의 책 "Expert One-on-One J2EE Design and Development" 에서 Java EE의 구조적 한계를 비판하며 EJB 없이도 충분히 확장 가능한 고품질의 애플리케이션을 작성할 수 있음을 약 3만줄의 코드로 보여줬다.

이것이 훗날 Spring Framework로 발전하게 된다.

 

~Spring이 제시한 방향~

컨테이너에 종속적이라 단위 테스트 어려움

> POJO 기반 프로그래밍: POJO는 Plain Old Java Object 의 약어로 그냥 순수한 Java 객체를 기반으로 개발하는 것을 말한다.

 

객체간의 결합도가 높아서 확장성이 낮음

> IoC: Inversion of Control, 즉 제어의 역전이라는 뜻. 기존에는 개발자가 객체의 생성부터 호출, 연결까지 해야했다. 하지만 IoC 컨테이너를 사용하면 이 컨테이너가 관리하는 객체는 Bean이라고 불리게 되고 컨테이너는 이 빈 객체들의 생성, 관리, 설정, 소멸까지 전 생명주기를 책임진다.

> DI: Dependency Injection, 의존성 주입이라는 뜻. 어떤 객체가 다른 객체를 필요로 할 때, 클래스에서 직접 다른 객체를 생성한다면 결합도가 높아진다. 이를 의존성 주입을 통해 해결할 수 있다. Spring은 IoC 컨테이너를 통해 의존성 주입을 수행한다.

 

또한 AOP( Aspect Oriented Programming ), 관점 지향 프로그래밍을 제공하여 공통되어 중복되는 로직을 따로 분리한 뒤 필요한 한 곳에 끼워넣는 식으로 코드의 모듈성을 향상 시키고 개발자가 비즈니스 로직에 집중할 수 있도록 해준다. 

 

 

프레임워크와 라이브러리의 차이점

 

프레임 워크는 어떤 문제를 해결하기 위한 일정한 구조와 기능을 제공하는 뼈대, 틀, 중간완성품 이다. 이것으로 개발자는 기능 구현에만 집중할 수 있다.

라이브러리는 단순 활용 가능한 도구들의 모음이다. 미리 작성된 메서드, 클래스 등이 포함된다.

둘의 차이점으론 제어권이 어디에 있냐가 있다. 

 

프레임워크는 애플리케이션의 전체적인 흐름을 이미 정해놓고 개발자는 그 흐름에 필요한 코드를 작성해주면 된다. (제어의 역전) Spring은 Framework이다.

 

그에 비해 라이브러리는 개발자가 flow의 주도권을 가지고 있으며 필요할 때 라이브러리를 가져다 쓰는 방식이다.

라이브러리의 예시로는 데이터 분석을 위한 python의 Pandas, 구글 브레인 팀에서 공개한 기계학습 라이브러리인 TensorFlow가 있다.

(텐서플로..케라스..쿠다.... 이녀석들 버전 맞추기가 너무 힘들었다... 처음 우분투 환경 구축부터 뭔가 잘못됐는지 새 프로젝트 할 때마다 버전 오류로 고생한 기억이.....나만그런가)

 

Spring Framework의 예시

개발자가  @Component와 @Autowired를 사용하여 Service에 필요로 하는 객체를 작성하면 Spring은 필요로 하는 객체를 알아서 생성하고, 주입해준다.

개발자가 @RestController, @GetMapping 같은 규칙을 준수하여 메서드를 작성하면 Spring이 요청을 받고 메서드를 호출하는 흐름을 알아서 제어한다.

 

Java 라이브러리의 예시

자바 표준 라이브러리인 java.util 패키지.

그 안엔 미리 정의된 인터페이스인 List 등이 있고 그 구현체로는 Arrat List, Linked List 등이 있다.

개발자는 필요할 때에 직접 호출하여 사용하여야 한다.