스프링 프레임워크(Spring Framework)
스프링 프레임워크(이하 스프링)는 Java에서 가장 많이 사용하는 프레임워크다.
스프링은 Java 언어로 엔터프라이즈급 개발을 편리하게 만들어주는 '오픈소스 경량급 애플리케이션 프레임워크'라고 불리고 있다. 여기서 엔터프라이즈급 개발은 기업환경을 대상으로 한 대규모 데이터를 처리할 수 있는 환경을 말한다.
즉, Java 언어를 이용한 대규모의 프로젝트를 보다 쉽게 만들 수 있도록 도와준다는 것이다.
스프링의 핵심 가치는 아래와 같다.
"애플리케이션 개발에 필요한 기반을 제공해서 개발자가 비즈니스 로직 구현에만 집중할 수 있도록 하는 것"
여러 가지 기술을 이용하여 복잡한 요소들을 스프링 프레임워크에 위임하고, 개발자는 비즈니스 로직 개발에만 집중할 수 있게 된다. 그중 가장 유명한 것은 IoC(제어의 역전), DI(의존성 주입), AOP(관점 지향 프로그래밍)으로 볼 수 있다.
이 세 가지에 대해 알아보자.
IoC(Inversion of Control) : 제어의 역전
IoC는 사용할 객체를 직접 생성하지 않고, 객체의 생명주기 관리를 외부(스프링 컨테이너)에 위임하는 것이다.
일반적으로 자바에서 객체는 아래와 같이 생성한다.
@RestController
public class NoneDIController {
private MyService service = new MyServiceImpl();
//Controller Codes
}
위와 같이 객체를 직접 생성한 뒤 그 객체에서 제공하는 기능을 사용한다. 즉, 객체를 생성하고 사용하는 작업을 개발자가 직접 제어하는 것이다.
그러나 스프링은 기본적으로 제어 역전(IoC)을 이용하여 개발자가 직접 객체를 생성하지 않고, 객체의 생명 주기 관리를 외부에 위임한다. 여기서 '외부'는 스프링에서 관리하는 Spring Container 또는 IoC Container라고 한다.
이렇게 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어의 역전이라고 부른다.
제어의 역전을 통해 의존성 주입(DI : Dependency Injection), 관점 지향 프로그래밍(AOP : Aspect-Oriented Programming)이 가능해진다. 이에 따라 개발자는 객체의 제어권을 컨테이너로 넘기고 객체의 생명 주기 관리 등의 복잡한 요소들을 신경 쓰지 않고, 비즈니스 로직에만 집중할 수 있게 된다.
DI(Dependency Injection) : 의존성 주입
의존성 주입은 제어 역전의 방법 중의 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 말한다.
위에서 일반적으로 자바에서는
@RestController
public class NoneDIController {
private MyService service = new MyServiceImpl();
//Controller Codes
}
이렇게 객체를 생성하고 사용한다고 했다.
그러나 스프링에서는 의존성 주입으로 직접 객체를 생성하지 않고 제어권을 스프링 컨테이너로 넘긴다.
의존성 주입 방법
의존성 주입 방법에는 세 가지가 있다.
- 생성자를 통한 의존성 주입
- 필드 객체 선언을 통한 의존성 주입
- setter를 통한 의존성 주입
@Autowired
스프링에서는 @Autwired라는 어노테이션(annotation)을 통해 의존성 주입을 명시할 수 있다.
스프링 4.3 이후 버전은 생성자 주입 시 @Autowired 어노테이션을 생략할 수 있다.
1. 생성자 주입
@RestController
public class DIController {
MyService myService;
@Autowired
public DIController(MyService myService) {
this.myService = myService;
}
//Controller Codes
}
2. 필드 주입
@RestController
public class DIController {
@Autowired
private MyService myService;
//Controller Codes
}
3. Setter 주입
@RestController
public class DIController {
MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
//Controller Codes
}
가장 좋은 방법
스프링 공식 문서에서 권장하는 의존성 주입 방법은 생성자를 통해 의존성을 주입받는 방법이다.
다른 방식과는 다르게 레퍼런스 객체 없이는 객체를 초기화할 수 업도록 설계하기 때문이다.
또한 위에서 스프링 4.3 이후 버전은 생성자 주입 시 @Autowired 어노테이션을 생략할 수 있다고 말했다.
이 점을 이용하고, 개발 편의성을 위한 라이브러리 롬복(Lombok)을 이용하여 아래와 같이 의존성 주입을 할 수 있다.
생성자 주입(롬복 이용)
@RestController
@RequiredArgsConstructor
public class DIController {
privite final MyService myService;
//Controller Codes
}
결과적으로 위와 같은 방법이 가장 좋은 의존성 주입 방법이라고 볼 수 있다.
롬복의 @RequiredArgsConstructor 어노테이션은 final이 붙은 필드의 생성자를 자동으로 생성해 준다.
AOP(Aspect-Oriented Programming) : 관점 지향 프로그래밍
AOP는 관점을 기준으로 묶어서 개발하는 방식을 의미한다.
어떤 기능을 구현할 때, 그 기능을 '핵심 기능'과 '부가 기능'으로 구분해 각각을 하나의 관점으로 보는 것이다.
상품 정보를 등록하고, 등록한 상품 정보를 조회하는 로직을 예로 들어보자.
클라이언트로부터 상품 정보 등록 요청을 받아서,
(1) 상품 정보를 데이터베이스에 저장하고, (2) 저장된 상품 정보를 조회하는 두 가지가 '핵심 기능'이다.
그러나 해당 기능을 개발할 때, 위의 핵심 기능 사이사이에 '부가 기능'을 추가할 상황이 생긴다.
예를 들면, 아래 그림과 같이 비즈니스 로직 사이사이, 데이터베이스 접근 시에 로깅과 트랜잭션을 추가해야 할 수 있다.
이때, 핵심 로직 사이사이에 존재하는 '부가 기능'인 로깅, 트랜잭션 등의 코드들은 핵심 기능과는 달리 동일한 기능을 수행할 확률이 높다.
AOP의 관점에서는 위와 같은 부가 기능들은 핵심 기능들과 상관없이 로직이 수행되기 전 또는 후에 수행되기만 하면 된다.
위의 코드에서 하나의 로직에서 로깅은 3번, 트랜잭션은 1번 수행된다.
이러한 반복되는 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화 해 삽입하는 방식을 AOP라고 한다.
스프링은 디자인 패턴 중 하나인 프락시 패턴을 통해 AOP 기능을 제공하고 있다.
스프링 AOP의 목적은 OOP(객체 지향 프로그래밍)과 마찬가지로 모듈화 해서 재사용 가능한 구성을 만드는 것이고,
이 또한 개발자가 비즈니스 로직 구현에만 집중할 수 있도록 도와준다.
정리
IoC(제어의 역전)
IoC(Inversion of Control)이란, 객체의 생성과 관리를 스프링 프레임워크가 대신해 주는 것을 말한다.
스프링 IoC 컨테이너라는 공간에서 객체의 생성과 의존성 관리를 대신해 준다.
IoC를 사용하면 객체 간의 의존성 관리가 용이해지며, 코드의 유지보수성과 확장성이 높아진다. 또한, 객체의 생명주기 관리나 AOP 등의 기능을 사용할 수 있게 된다.
DI(의존성 주입)
DI(Dependency Injection)이란, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 말한다. DI를 이용하면 객체 간의 의존성을 줄이고 유지보수성을 높일 수 있다.
스프링에서는 생성자 주입, 필드 주입, Setter 주입 3가지의 방식으로 DI를 구현할 수 있고, 생성자 주입이 가장 권장되는 방법이다.
AOP(관점 지향 프로그래밍)
AOP(Aspect-Oriented Programming)이란, 관점을 기준으로 묶어서 개발하는 방식을 의미한다.
애플리케이션의 '핵심 기능'과 '부가 기능'으로 분리항 모듈화 하는 개념이다.
AOP를 사용하면 부가 기능의 코드 중복을 줄이고, 유지보수성을 높일 수있다.
또한 스프링은 프락시 패턴을 이용하여 AOP를 구현한다.
이 글은 '스프링 부트 핵심 가이드' 책을 참고하여 썼습니다.
'컴퓨터 공학 > 프로그래밍 이론' 카테고리의 다른 글
[Spring Boot] DispatcherServlet - 스프링부트의 동작 구조 (0) | 2024.01.22 |
---|---|
[Spring / 스프링 부트 핵심 가이드] 디자인 패턴 정리 (0) | 2023.10.01 |
[ComputerScience / 디자인 패턴] 브릿지 패턴(Bridge Pattern, 가교 패턴) (0) | 2023.10.01 |
[Spring / 스프링 부트 핵심 가이드] 레이어드 아키텍처, SpringMVC (0) | 2023.10.01 |
[ComputerScience / 디자인 패턴]싱글톤 패턴(singleton pattern) (0) | 2023.04.20 |