사용하는 이유
- 의존성 관리(DI)와 객체 생명 주기 관리가 편리함
- 스프링은 DI(Dependency Injection)를 통해 객체 간의 의존성을 효율적으로 관리함
- 개발자는 객체 생성과 의존성 주입을 스프링이 대신 처리해 주므로 코드가 간결해지고 유지보수성이 향상됨
- 비즈니스 로직과 공통 관심사를 분리할 수 있음(AOP)
- 스프링의 AOP(Aspect-Oriented Programming)를 통해 트랜잭션 관리, 로깅, 보안과 같은 공통 관심사를 비즈니스 로직에서 분리할 수 있음
- 이를 통해 코드 중복을 줄이고 유지보수성을 높일 수 있음
- 유연하고 확장 가능한 구조 제공
- 스프링은 모듈화된 구조로 필요한 기능만 선택적으로 사용할 수 있음
- 스프링 부트를 사용하면 프로젝트 설정과 배포를 간소화할 수 있음
- 강력한 생태계와 커뮤니티 지원
- 스프링은 Spring Security, Spring Data, Spring Cloud 등 다양한 서브 프로젝트를 제공하며, 개발에 필요한 거의 모든 기능을 지원함
- 커뮤니티와 문서가 잘 갖춰져 있어 실무에서 문제 해결이 용이함
동작 원리
- IoC (제어의 역전)
- 객체의 생명과 생명주기를 개발자가 아닌 스프링 컨테이너가 관리하는 방식
- 객체 간 결합도를 낮추고 더 유연한 구조를 제공함
- DI (의존성 주입)
- 스프링 컨테이너는 객체 간 의존성을 설정 파일이나 어노테이션을 참고해 주입
- 개발자가 직접 new를 이용해 객체를 생성하는 대신 외부에서 객체를 만들어서 주입시키는 방식
- 의존 관계를 외부에서 주입하여 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높임
- DI와 IoC의 차이점: DI는 IoC의 한 구현 방식. IoC는 일반적인 개념이고 DI는 이를 구현하는 구체적인 방법
- 스프링에서 구현 방법
- @Autowired 나 @RequiredArgsContructor로 구현할 수 있음
- 생성자 주입, 세터 주입, 필드 주입. 그 중 생성자 주입이 권장되며 이는 불변성을 보장하고 순환 의존성을 방지하는데 도움이 됨
- @Autowired 대신 생성자 주입을 사용하는 이유
- 불변성 보장: 의존성이 final로 선언되어 변경될 수 없음
- 테스트 용이성: 의존성을 주입받는 객체를 쉽게 생성할 수 있어 단위 테스트가 용이함
- 순환 의존성 방지: 컴파일 시점에 순환 의존성을 감지하여 오류를 예방할 수 있음
- AOP
- 스프링은 횡단 관심사를 핵심 로직과 분리하기 위해 AOP를 사용함
- 이를 통해 코드 중복을 줄이고, 비즈니스 로직의 가독성을 높일 수 있음
- 프록시 기반으로 IoC 컨테이너에서 빈을 생성하는 시점에 AOP를 적용할지 여부를 판단하여 프록시 빈을 생성한다. 이 과정에서 JDK Proxy와 CGLIB 둘 중에 선택해서 프록시 빈을 생성하는데, 일반적으로 타깃이 인터페이스를 구현하고 있는 경우 JDK Proxy 방식, 타깃의 객체가 인터페이스를 구현하지 않으면 CGLIB 방식으로 프록시가 생성된다.
- 이 프록시의 핵심적인 기능은 지정된 메서드가 호출될 때 이 메소드를 가로채어 부가 기능들을 추가할 수 있도록 지원하는 것이다.
- Self-Invocation (자가호출)
- 같은 클래스 내에서 AOP가 적용된 메서드를 호출할 때 발생
- 발생 이유
- AOP는 프록시 기반으로 동작함
- 내부 매서드 호출 시 프록시를 거치지 않고 실제 객체의 메서드를 직접 호출
- 결과적으로 AOP 어드바이스(트랜잭션 등)가 적용되지 않음
- 해결 방법
- 자가 호출을 피하고 별도의 클래스로 분리
- AopContext.currencyProxy()를 사용하여 프록시를 통해 호출
- 자가 호출하는 메서드를 별도의 빈으로 뷴리하여 주입받아 사용
- MVC
- 클라이언트(브라우저)에서 HTTP요청이 발생하면 DispatcherServlet이 요청을 받음
- DispatcherServlet은 HandlerMapping을 사용하여 어떤 컨트롤러가 이 요청을 처리할지 결정
- 선택된 컨트롤러가 요청을 처리하고, 필요한 비즈니스 로직을 수행하여 모델을 업데이트
- HandlerAdapter는 DispatcherServlet의 처리 요청을 변환해서 컨트롤러에게 전달
- 컨트롤러는 모델과 사용할 뷰의 정보를 포함한 ModelAndView 객체를 HandlerAdaper에게 반환
- DispatcherServlet은 ViewResolver를 사용하여 뷰를 선택하고 모델을 전달
- 뷰는 모델의 데이터를 사용하여 클라이언트에게 응답을 생성
다형성을 활용하여 서비스 계층을 설계하는 방법
인터페이스를 기반으로 여러 구현체를 만들어 특정 비즈니스 로직에 따라 다른 구현체를 주입
예를 들어, PaymentService 인터페이스를 정의하고 CreditCardPaymentService, PayPalPaymentService 등의 구현체를 만듦
그리고 주문 서비스에서 PaymentService 인터페이스를 주입받아 결제 방식을 동적으로 선택함
코드 재사용성, 유지보수성이 향상되며 비즈니스 로직에서 코드변경 없이 새로운 결제 방식을 쉽게 추가할 수 있음
728x90
반응형
'Java & Kotlin > Spring' 카테고리의 다른 글
Spring @Transaction (0) | 2025.01.14 |
---|---|
Spring Filter & Interceptor (0) | 2025.01.13 |
Spring JPA (0) | 2025.01.12 |
Spring Boot AutoConfiguration (0) | 2025.01.11 |