[Spring] 스프링의 주요한 특징
스프링이란?
스프링이란?
스프링이란 자바 기반 프레임워크이다. 스프링 프레임워크는 순수 자바로 작성된 프로젝트에 비해 단순하고 직관적이라는 장점을 가지게 된다. 프레임워크를 사용함으로서 생산성이 향상되며 특정한 패턴을 가지므로 유지 보수력이 올라간다. 스프링 프레임워크는 아래의 특징들을 가진다.
아래의 그림이 스프링의 전체적인 형태를 잘 나타내고 있다.
스프링의 특징
1. 스프링 컨테이너 사용
- 스프링 컨테이너가 객체의 생명주기를 관리한다.
- 의존성 주입을 처리한다.
- 빈(Bean)이라 불리는 객체 인스턴스를 관리한다.
- 즉 객체의 생성 및 의존성 관리를 프레임워크 차원에서 관리해주어 유연성, 확장성, 유지보수성을 향상시켜준다.
2. 제어 역전(Inversion of Control, IoC)
- 객체의 관리를 개발자가 아닌 프레임워크가 담당한다.
- 즉, 스프링 프레임워크가 객체의 생성, 초기화, 종료 등의 작업을 처리한다.
- 이를 위해 위에서 설명한 스프링 컨테이너를 사용한다.
3. 의존성 주입(Dependency Inhection, DI)
- 외부(스프링 컨테이너)에서 두 객체의 관계를 결정해주는 디자인 패턴이다.
- 인터페이스를 사이에 배치해 결합도를 느슨하게 하고, 의존관계가 고정되지 않도록 한다.
- 즉 기존에 한 클래스 내에서 다른 클래스의 객체를 생성하는 방식을, 외부에서 객체를 받아오는 방식으로 설정하는 것이다.
의존성 주입의 일반적인 방법은 아래의 세 가지이다.
의존성 주입
- 생성자 주입(Constructor Injection): 객체를 생성할 때 생성자를 통해 의존하는 객체를 주입한다. 주입받을 의존 객체를 매개변수로 받는 생성자를 정의하고, 스프링 컨테이너는 해당 생성자를 호출하여 의존 객체를 주입합니다.
- 세터 주입(Setter Injection): 의존 객체를 설정하는 세터 메서드를 통해 주입합니다. 의존 객체를 설정하는 메서드를 정의하고, 스프링 컨테이너는 해당 메서드를 호출하여 의존 객체를 주입합니다.
- 필드 주입(Field Injection): 객체의 필드에 직접 의존 객체를 주입합니다. 의존 객체를 주입받을 필드를 정의하고, 스프링 컨테이너는 해당 필드에 의존 객체를 주입합니다. 이 방식은 주로 애노테이션을 사용하여 주입을 표시합니다.
4. 관점 지향 프로그래밍(Aspect Oriented Programming, AOP)
- 객체 지향 프로그래밍을 발전시킨 개념
- 어플리케이션의 횡단 관심사(Cross-cutting Concerns)를 모듈화하여 재사용성, 유지보수성을 향상
어플리케이션은 비즈니스 로직과 이 비즈니스 로직을 지원하는 공통 로직을 포함한다. 이때, 이 공통 로직은 여러 비즈니스 로직에서 중복되어 사용된다.
AOP에서는 이러한 공통 로직을 관점이라는 단위로 모듈화하여 핵심 비즈니스 로직에서 분리하여 적용한다.
예를 들어 아래와 같이 구분이 되겠다.
Core Concern(핵심 관심) : 각 서비스의 핵심 로직. ex)계좌이체, 통장 잔고 확인
Crosscut Concern(횡단 관심) : 핵심 기능이 아닌 서비스에 (공통으로) 삽입되어야 할 기능 ex)보안, 로깅, 트랜잭션
객체 지향 프로그래밍의 특징
- 캡슐화
- 은닉
- 추상화
- 상속
- 다형성
- SOLID 원칙
https://doompa.tistory.com/303
5. POJO(Plain Old Java Object) 지향
- 일반적인 자바 객체를 의미하며, 일반적인 자바 객체를 사용한다.
- 특정한 자바 버전 (Java EE)나 특정 프레임워크에 종속되지 않는 순수한 자바 객체를 의미한다.
- 특정 인터페이스, 클래스를 구현하거나 상속받지 않는다.
- 자바 빈 규약에 따라 기본 생성자, 캡슐화된 멤버 변수(private), 게터, 세터를 가진다.
- 스프링은 이러한 POJO를 기반으로 어플리케이션을 개발한다.
- 이렇게 구현함으로서 의존도를 떨어뜨린다. 예를 들어 특정 라이브러리 등에 의존 할 경우 해당 라이브러리가 바뀔 경우 코드가 작동 안 할 수 있다. 이를 미연에 방지한다.
생성자 주입 예시
public class UserService {
private UserRepository userRepository;
// 생성자를 통한 의존성 주입
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
UserService클래스는 UserRepository클래스에 의존한다(즉 UserRepository클래스를 사용하여야한다)
public class Main {
public static void main(String[] args) {
// UserRepository 객체를 생성
UserRepository userRepository = new UserRepository();
// UserService 객체를 생성하면서 UserRepository 객체를 주입
UserService userService = new UserService(userRepository);
}
}
메인문에서 객체를 생성하여 생성자에 직접 넣는다. 이 방식이 생성자 주입이다. (명시적 방법)
아래의 방법 역시 가능하다.
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
생성자 주입은 스프링 팀에서 제일 권장하는 방식의 의존성 주입이다. 위 @Autowired를 사용하지 않은 방법의 경우 생성자 주입을 직접 구현하였고, 아래 @Autowired의 경우 스프링이 자체적으로 의존성 주입을 처리해준다.
생성자 주입의 경우 해당 객체(UserService)가 생성될 때 한 번만 주입될 것을 보장해준다.
단, 두 번째 방법의 경우 UserRepository 객체가 빈에 등록되어 있어야한다.