1.1 스프링 프레임워크

김찬미·2024년 5월 28일
0

스프링 프레임워크란?

스프링 프레임워크(=스프링)는 Java 기반의 애플리케이션 프레임워크로 엔터프라이즈급 애플리케이션을 개발하기 위한 다양한 기능을 제공한다. 스프링은 목적에 따라 다양한 프로젝트를 제공하는데, 그 중 하나가 Spring Boot이다.

자바(Java)에서 가장 많이 사용하는 프레임워크이며, 현재 우리나라의 공공기간 웹 서비스를 개발할 때에도 사용된다. 스프링은 자바 언어를 이용해 *엔터프라이즈급 개발을 편리하게 만들어주는 '오픈소스 경량급 애플리케이션 프레임워크'로 불리기도 한다. 쉽게 말해 자바로 애플리케이션을 개발하는 데 필요한 기능을 제공하고 쉽게 사용하도록 돕는 도구이다.

엔터프라이즈급 개발 : 기업 환경을 대상으로 하는 개발, 대규모 데이터를 처리하는 환경에 알맞게 설계

스프링의 핵심 가치는 "애플리케이션 개발에 필요한 기반을 제공해 개발자가 비즈니스 로직 구현에만 집중할 수 있게끔 하는 것"이다. 여기서부턴 위와 같은 스프링을 효율적으로 사용할 수 있도록 스프링의 특징과 구조 등을 알아보도록 하겠다.

스프링의 특징과 구조

- 제어 역전 (IoC)

일반적인 자바 개발의 경우 사용하려는 객체를 선언하고, 해당 객체의 의존성을 생성한 후 객체에서 제공하는 기능을 사용하는 일련의 절차를 거친다. 객체를 생성하고 사용하는 일련의 작업을 개발자가 직접 제어하는 구조이다.

그러나 IoC를 적용한 환경에서는 객체의 제어권을 개발자가 아닌 컨테이너(스프링 프레임워크)가 가진다. 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 제어 역전이라고 부르며, 제어 역전을 통해 DI, AOP등이 가능해진다.

스프링을 사용하면 객체의 제어권(객체의 생성, 초기화, 의존성 등의 관리)을 컨테이너로 넘기기 때문에 개발자는 비즈니스 로직을 작성하는 데 더 집중할 수 있다.


- 의존성 주입 (DI)

의존성 주입(DI; Dependency Injection)이란 제어 역전의 방법 중 하나로, 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식을 의미한다.

스프링에선 @Autowired라는 *어노테이션을 통해 의존성을 주입할 수 있다. 스프링 4.3 이후 버전에서는 생성자를 통해 의존성을 주입할 때 @Autowired 어노테이션을 생략할 수도 있지만, 스프링을 처음 다룰 때는 가독성을 위해 어노테이션을 명시하길 권장한다.

어노테이션(Annotation)은 자바 프로그래밍 언어의 기능 중 하나로, 소스 코드에 메타데이터를 추가하는 방법이다. 이 메타데이터는 컴파일러, 런타임 시스템 또는 다른 소프트웨어 도구에게 정보를 제공하여 코드를 처리하거나 처리하는 방법을 지시한다.
예를 들어, 스프링 프레임워크에서는 @Controller, @Service, @Autowired 등의 어노테이션을 사용하여 클래스나 메서드에 특정한 의미를 부여한다. 이러한 어노테이션을 사용함으로써 스프링 컨테이너가 빈을 관리하거나 의존성을 주입하는 등의 작업을 수행할 수 있다.
즉, 어노테이션은 자바 소스 코드에 부가적인 정보를 제공하여 컴파일러나 런타임 시스템에게 특정 작업을 수행하도록 지시하는 역할을 한다.

스프링에서 의존성을 주입받는 방법은 세 가지가 있다.

  • 생성자를 통한 의존성 주입
@Controller
public class UserController {
	private UserService userService;
    
    // 생성자 주입
    @Autowired  // 생략 가능 (스프링 4.3 이상)
    public UserController(UserService userService) {
        this.userService = userService;
    }

	public void execute {
    	userService.performService();
    }
}

@Autowired 어노테이션을 생성자에 사용하여 스프링이 자동으로 의존성을 주입하도록 한다. 이 방식은 불변성(immutability)을 보장하고, 주입할 객체를 테스트하기 쉽다는 장점이 있다. 스프링 공식 문서에서 권장하는 의존성 주입 방법 또한 바로 생성자를 통해 의존성을 주입받는 방식이다.

번외) @RequiredArgsConstructor란?

@RequiredArgsConstructor 어노테이션은 롬복(Lombok) 라이브러리를 사용하여 생성자 주입을 간결하게 처리할 수 있게 한다. 이 어노테이션은 final이나 @NonNull 필드를 포함한 생성자를 자동으로 생성해준다. 이는 스프링 4.3 이후 버전에서 가능한 기능이다.

@RequiredArgsConstructor
@Controller
public class UserController {
	private final UserService userService;

	public void execute {
    	userService.performService();
    }
}

@RequiredArgsConstructor을 이용하면 매번 새로운 필드를 추가할 때마다 생성자를 새로 생성해야 하는 번거로움이 없어지기 때문에 상당히 간편하다.

  • 필드 객체 선언을 통한 의존성 주입
@Controller
public class UserController {
	@Autowired
	private UserService userService;
}

필드에 @Autowired 어노테이션만 붙여주면 자동으로 의존성이 주입된다. 이 방법은 코드가 간결하지만 필드가 외부에서 설정하기 때문에 테스트하기 어렵고, 불변성을 보장하지 않으며 순환 의존성 문제가 발생할 수 있기에 추천되지 않는다.

  • setter 메서드를 통한 의존성 주입
@Controller
public class UserController {
	private UserService userService;
    
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

Setter 메소드에 @Autowired 어노테이션을 붙이는 방법이다. 이 방식은 객체 생성 후에도 의존성을 변경할 수 있기 때문에 유연성이 있다. 그러나 의존성이 누락될 가능성이 있어, 의존성이 필수적인 경우 생성자 주입보다 안전하지 않다.


- 관점 지향 프로그래밍 (AOP)

관점 지향 프로그래밍 (AOP; Aspect-Oriented Programming)은 스프링의 아주 중요한 특징이다. 자바의 특징으로는 객체지향 프로그래밍(OOP; Object-Oriented Programming)이 있는데, AOP는 OOP를 더욱 잘 사용하도록 돕는 개념으로 보는 것이 좋다.

AOP는 관점을 기준으로 묶어 개발하는 방식을 의미한다. 여기서 관점(aspect)이란 어떤 기능을 구현할 때 그 기능을 '핵심 기능'과 '부가 기능'으로 구분해 각각을 하나의 관점으로 보는 것을 의미한다.

  • 핵심 기능 : 프로그램의 주요 기능 또는 핵심 로직을 나타낸다. 이 기능은 프로그램의 주요 목적을 달성하기 위해 필수적인 부분이다.

  • 부가 기능 : 프로그램의 여러 부분에서 반복되는 코드 또는 관심사를 나타낸다. 이러한 기능은 프로그램의 핵심 기능과는 별개로, 보안, 로깅, 트랜잭션 관리 등과 같은 작업을 포함한다.

실제 애플리케이션을 개발할 때는 핵심 기능에 부가 기능을 추가할 상황이 생긴다. 이 애플리케이션에는 로그인 기능이 있고, 로그인 할 때마다 로깅을 해야 한다. AOP를 사용하면 각 로그인 메서드에 로깅 코드를 직접 추가하는 대신 로그인 메서드 실행 전후에 로깅을 수행하는 관점을 정의할 수 있다.

// 핵심 기능
public class LoginService { 
    public void login(String username, String password) {
        // 로그인 로직
        System.out.println("로그인 성공: " + username);
    }
}

// 부가 기능
public aspect LoggingAspect { 
    before(): execution(* LoginService.login(..)) {
        // 로그인 메서드 실행 전에 로깅
        System.out.println("로그인 시도 중...");
    }
}

위 코드에서 LoginService 클래스는 로그인 기능을 담당하는 핵심 기능이다. 그리고 LoggingAspect는 AOP를 이용하여 로깅 관심사를 처리하는 부가 기능이다. before() 라는 어드바이스(advice)를 사용하여 LoginService 클래스의 login 메서드가 실행되기 전에 로깅을 수행하도록 지정한 것이다. 이렇게 하면 LoginService 클래스의 코드를 수정하지 않고도 로깅 기능을 추가할 수 있다.

요약하면, AOP는 프로그램의 여러 부분에서 반복되는 코드를 분리하여 관리할 수 있는 유용한 기술이다. AOP에 관점에서는 부가 기능은 핵심 기능이 어떤 기능인지에 무관하게 로직이 수행되기 전 또는 후에 수행되기만 하면 된다.

이처럼 여러 비즈니스 로직에서 반복되는 부가 기능을 하나의 공통 로직으로 처리하도록 모듈화해 삽입하는 방식을 AOP라고 한다. AOP의 목적은 OOP와 마찬가지로 모듈화해서 재사용 가능한 구성을 만드는 것이고, 모듈화된 객체를 편하게 적용할 수 있게 함으로서 개발자가 비즈니스 로직을 구현하는 데만 집중할 수 있게 도와주는 것이다.


스프링 프레임워크의 다양한 모듈

스프링 프레임워크는 기능별로 구분된 약 20여 개의 모듈로 구성되어 있다. 아래 그림은 스프링 공식 문서에서 제공하는 다이어그램이다.

스프링 프레임워크 공식 문서에서는 버전별로 다른 다이어그램을 제시하고 있지만 큰 틀은 유사하다. 그리고 스프링 프레임워크를 사용한다고 해서 꼭 모든 모듈을 사용할 필요는 없다. 애플리케이션 개발에 필요한 모듈만 선택해서 사용하게끔 설계되어 있으며, 이를 경량 컨테이너 설계라고 부른다.


profile
백엔드 개발자

0개의 댓글

관련 채용 정보