스프링 프레임워크의 특징
제어의 역행 (IoC)
Inversion of Control 애플리케이션의 느슨한 결합을 도모. 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어 필요에 따라 스프링에서 사용자의 코드를 호출한다.
- 팩토리 패턴을 사용하여 객체 간의 결합도를 줄여 가독성을 좋게 하고, 코드 중복을 최소화하며, 유지보수를 편하게 할 수 있습니다.
- 기존에 사용자가 모든 작업을 제어하던 것을 컨테이너에게 위임하여 객체의 생성부터 생명주기 등 모든 객체에 대한 제어권이 넘어 간 것을 IoC라고 합니다.
BeanFactory
BeanFactory 인터페이스는 IoC컨테이너의 기능을 정의하고 있는 인터페이스이며, Bean의 생성 및 의존성 주입, 생명주기(lifecycle) 관리 등의 기능을 제공한다.
클라이언트의 요청에 의해서 Bean 객체가 사용되는 시점(Lazy Loading)에 객체를 생성
ApplicationContext(Spring 컨테이너, IoC 컨테이너)
BeanFactory 인터페이스를 상속받는 ApplicationContext는 BeanFactory가 제공하는 기능 외에 AOP, 트랜잭션 관리 등의 기능을 제공한다.
컨테이너가 구동되는 시점에 객체들을 생성하는 Pre-Loading 방식
애플리케이션 실행 시점에 오류를 즉시 발견할 수 있다.
- 트랜잭션 이란 쉽게 말해 처리 단위를 뜻한다.
의존성 주입(DI)
제어의 역행이 일어나는 것을 전제로 하여 스프링 내부의 객체들간의 관계를 만들어줄 때 사용합니다.
외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
빈(Bean) 설정파일에 의존관계가 필요한 정보를 추가해주면 컨테이너가 자동적으로 연결해준다.
- 각각의 계층이나 서비스들 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
- 의존성 주입은 말 그대로 특정 객체가 필요로 하는 객체를 외부에서 결정하여 연결시키는 것을 말합니다.
POJO 기반의 구성
POJO는 Plain Old Java Object로, 평범한 자바 객체를 말합니다.
이 단어는 마틴 파울러가 2000년에 컨퍼런스 발표를 준비하다가 만들어낸 용어인데, 단순히 발표 중의 "간단한 자바 오브젝트를 사용하는데요~"라고 하는 것보다 "POJO 방식의 기술을 사용하는데요~"라고 하면 왠지 세련되고 첨단 기술을 쓰는 것처럼 느껴진다는 심리를 이용하여 만들어진 것이라고 합니다. 그래서 우리가 자바에서 개발하는 지극히 평범한 객체를 POJO라고 합니다.
다만, POJO는 특정 규약과 특정 환경에 종속되어서는 안 되고 객체지향 설계를 잘 지켜야한다는 조건이 있습니다.
AOP 지원
AOP(Aspect Oriented Programming)는 관점 지향 프로그래밍을 뜻합니다.
대부분의 시스템에서 비즈니스 로직은 아니지만 보안, 로그, 트랜잭션과 같이 반드시 처리가 필요한 부분을 횡단 관심사라고 합니다. 스프링에서는 이러한 관심사를 비즈니스 로직과 분리하여 중복된 코드를 줄이고 개발자가 비즈니스 로직에 집중하도록 만들어 줍니다.
- 관점지향 프로그래밍(AOP : Aspect-Oriented Programming) : 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.
오버라이딩(Overriding)
부모 클래스에서 상속받은 자식 클래스에서 부모클래스에서 만들어진 메서드를 자식 클래스에서 자신의 입맛대로 다시 재정의해서 사용하는 것을 말한다.
- 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다
- 로미오와 줄리엣의 역할 → 구현체로 장동건과 원빈, 그리고 김태희와 송혜교 등
- 자동차라는 역할 → 구현체로 K3, 아반떼, 테슬라 모델3 등이 있습니다.
의존성 주입 DI (@Autowired , @Component)
컨테이너에서 필요한 의존 객체의 타입에 해당하는 빈 객체를 찾아 주입한다.
생성자, 필드, setter에 Autowired를 사용할 수 있다.
1)생성자 주입
생성자를 통해 의존 관계를 주입하는 방법
생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장된다. 그렇기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다. 또한 생성자가 1개만 있을 경우에 @Autowired를 생략해도 주입이 가능하도록 편의성을 제공한다.
2) 세터 주입
필드 값을 변경하는 Setter를 통해서 의존 관계를 주입하는 방법
Setter 주입은 생성자 주입과 다르게 주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.
3)필드 주입
필드에 바로 의존 관계를 주입하는 방법
필드 주입을 이용하면 코드가 간결해져서 과거에 상당히 많이 이용되었던 주입 방법이다. 하지만 필드 주입은 외부에서 변경이 불가능하다는 단점이 존재하는데, 점차 테스트 코드의 중요성이 부각됨에 따라 필드의 객체를 수정할 수 없는 필드 주입은 거의 사용되지 않게 되었다. 또한 필드 주입은 반드시 DI 프레임워크가 존재해야 하므로 반드시 사용을 지양해야 한다.
생성자 주입(Constructor Injection)을 사용해야 하는 이유
1)객체의 불변성 확보
의존 관계 주입의 변경이 필요한 상황은 거의 없다. 하지만 수정자 주입이나 일반 메소드 주입을 이용하면 불필요하게 수정의 가능성을 열어두게 되며, 이는 OOP의 5가지 개발 원칙 중 OCP(Open-Closed Principal, 개방-폐쇄의 법칙)를 위반하게 된다. 그러므로 생성자 주입을 통해 변경의 가능성을 배제하고 불변성을 보장하는 것이 좋다.
2)테스트 코드의 작성
필드 주입으로 작성된 경우 테스트 코드가 Spring과 같은 DI 프레임워크 위에서 동작하지 않으므로 의존 관계 주입이 되지 않기 때문에 순수한 자바 코드로 단위 테스트를 작성하는 것이 불가능하다.
3)final 키워드 작성 및 Lombok과의 결합
생성자 주입을 사용하면 필드 객체에 final 키워드를 사용할 수 있으며, 컴파일 시점에 누락된 의존성을 확인할 수 있다. 반면에 생성자 주입을 제외한 다른 주입 방법들은 객체의 생성(생성자 호출) 이후에 호출되므로 final 키워드를 사용할 수 없다.
또한 final 키워드를 붙임으로써 Lombok과 결합되어 코드를 간결하게 작성할 수 있다. Lombok에는 final 변수를 위한 생성자를 대신 생성해주는 @RequiredArgsConstructor가 있다.
Spring Bean
Spring 컨테이너가 관리하는 객체를 빈(Bean)이라고 부릅니다. IoC 컨테이너 안에 들어있는 객체를 필요할 때 IoC 컨테이너에서 가져와서 사용합니다.
스프링 Bean을 IoC 컨테이너에 등록하는 방법
1)Component scan
- @ComponentScan 어노테이션과 @Component 어노테이션을 사용해서 빈을 등록하는 방법
- @ComponentScan: 어느 지점부터 컴포넌트를 찾으라고 알려주는 역할
- @Component: 실제로 찾아서 빈으로 등록할 클래스
2) 빈 설정 파일에 직접 등록
- XML 파일이나 설정 파일로 작성할 수 있음
- 자바 설정 파일: @Configuration 어노테이션을 붙인 클래스에 @Bean 어노테이션을 사용해 직접 빈을 정의할 수 있음
@Component
- IoC 컨테이너에 Bean을 등록하기 위해 사용
- 개발자가 작성한 class를 기반으로 런타임 시에 컴포넌트 스캔하여 인스턴스 객체를 생성합니다.
- @Controller, @Service, @Repository 모두 @Component이며 실행시점에 자동으로 의존성을 주입합니다.
@Bean
- IoC 컨테이너에 Bean을 등록하기 위해 사용
- 개발자가 작성한 메소드를 기반으로 메서드에서 반환하는 객체를 인스턴스 객체로 생성합니다.
스프링 Bean의 Scope
빈 스코프는 빈이 존재할 수 있는 범위를 뜻하며 싱글톤, 프로토타입, request, session 등이 있다.
@Scope
- singleton: 기본 스코프로 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
- prototype : 애플리케이션 요청시( getBean() 메서드가 호출될 때마다) 스프링이 새 인스턴스를 생성합니다.
- request : HTTP 요청별로 인스턴스화 되며 요청이 끝나면 소멸됩니다.
- session : HTTP 세션별로 인스턴스화 되며 세션이 끝나면 소멸됩니다.
- thread : 새 스레드에서 요청하면 새로운 bean 인스턴스를 생성합니다. 같은 스레드의 요청에는 항상 같은 인스턴스가 반환됩니다.
- custom : org.pringframework.beans.factory.config.Scope 인터페이스를 구현하고 커스텀 스코프를 스프링의 설정에 등록하여 사용합니다.
연관된 글:
[CS] 좋은 객체 지향 설계의 5대 원칙: SOLID
참고 :
@Controller, @Service, @Repository 차이
[Spring] 스프링 빈(Bean)의 개념과 생성 원리
[Spring] 다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유 - (2/2)
'개발 > Spring' 카테고리의 다른 글
[Spring] 스프링시큐리티(Spring Security) 개념 (0) | 2023.04.26 |
---|---|
[Spring] JPA와 ORM (0) | 2023.03.22 |
[Spring] 어노테이션 모음집 (0) | 2023.03.08 |
[Spring] QueryDSL (0) | 2023.02.20 |
[Spring] Spring Boot (0) | 2023.02.10 |