Spring 핵심 개념 총정리 (DI, IoC, Filter, Interceptor, AOP)

Jihye Gim·2026년 3월 19일

Codeit SB11

목록 보기
8/22

스프링 DI, IOC 기타..

https://howtodoinjava.com/spring-core/spring-ioc-vs-di/

스프링 DI (Dependency Injection)
Spring은 객체 간 의존관계를 프레임워크가 관리하는 IoC(Inversion of Control) 원칙에 따라 의존성을 제공한다. DI는 객체가 직접 필요한 의존 대상을 만드는 것이 아니라, 스프링 컨테이너 객체(Bean)간의 의존 관계를 외부에서 주입해주는 것을 의미한다.
이를 통해 구성(구현/생성)의 책임이 코드에서 컨테이너로 이동해, 느슨한 결합(loose coupling)을 실현할 수 있다.

1. DI(의존성 주입)란?

- 의존성 : 어떤 객체가 동작하는데 꼭 필요한 다른 객체(예: Service에서 Repository 등).
- 주입(Injection): 이런 의존성을 개발자가 직접 new로 만드는 대신, 외부(주로 스프링 프레임워크)가 대신 만들어서(생성/관리) 넣어주는 것.

2. 쓰는 이유?

- 코드를 더 유연하게
	- 개발자는 "이 객체를 어떻게 만들지"가 아니라 "이 객체가 필요하다"는 선언만 하면 됨
- 테스트 코드 작성이 쉬움
	- 가짜 객체(mock,stub)를 쉽게 "주입" 해서 단위테스트 가능
- 코드 재사용, 유지보수에 강함
	- 직접 생성하지 않으니 구조 바꿔도 코드 수정 최소화

3. 스프링 컨테이너란?

- 스프링에서는 객체(Bean)의 "생명주기 관리" 까지 자동으로 해주는 "컨테이너"가 있다. DI는 여기서 자동으로 객체를 찾아서 넣어주는 기능이다.

4. 주입하는 방법

1) Constructor Injection(생성자 주입(권장))
```
@Service
public class UserService {
	private final UserRepository userRepository;
	
	// 생성자에 파라미터로 의존성을 적어줌
	public UserService(UserRepository userRepository) {
		this.userRepository = userRepostitory;
	}
}
```
2) 필드 주입
@Service
public class UserService {
	@Autowired
	private UserRepository userRepository;
}
// 코드가 짧지만, 테스트/유지보수에 불리해서 권장하지 않음
3) Setter/Property Injection (Setter 주입)
@Service
public class UserService {
	private final UserRepository userRepository;
	
	@Autowired
	public void setUserRepository(UserRepository userRepository) {
		this.userRepository = userRepository;
	}
}

5. @Component @Service @Repository @Controller

  • DI 가 잘 동작하려면, 클래스에 위와 같은 애너테이션으로 "스프링이 관리하는 Bean"으로 등록해줘야 한다.

6. 실제 동작 흐름

1. 스프링 애플리케이션 실행
2. 스프링 컨테이너가 Bean들을 자동으로 생성/등록 하고
3. 개발자가 선언한 의존성에 맞춰 DI 수행(생성자, Setter 등)의존하는 객체들을 "알아서" 주입해줌
4. 필요시(어플리케이션 종료 등) Bean 소멸 등 라이프사이클 관리도 컨테이너가 처리
@Service
public class OrderService {
	private final PaymentService paymetService;
	
	public OrderService(PaymentService paymentService) {
		this.paymentService = paymentService; // 스프링이 자동으로 넣어줌
	}	
}
  • OrderServicePaymentService 를 쓴다는 "의존성"만 선언
  • 스프링의 DI가 자동으로 PaymentService 객체를 대신 넣어줌

7. 참조(Reference)와 값(Valuse) 주입의 차이

- ref: 다른 Bean(객체)을 주입
- valuse: 간단한 값(문자열, 숫자 등)주입

8. 컬렉션(리스트, 셋, 맵 등)도 DI 가능

 - 여러 의존성 객체를 List, Set, Map 형태로 한꺼번에 주입 가능

9. 내부 Bean과 외부 Bean 구분

- Bean 내부에 또 다른 Bean을 선언해서 사용할 수도 있음(scope 등 다양한 설정 가능)

10. 느슨한 결합(Loose coupling) 및 설계 유연성 강조

  • 스프링 DI 방식은
    - 객체가 자신이 쓸 "구현체"에 직접 의존하지 않고
    - 외부(컨테이너)가 알아서 객체를 넣어주므로 -> 코드 변경이 적고, 테스트가 쉽고, 구조가 유연함.

IoC란?

  • Inversion of Control(제어의 역전)
    - 프로그램의 흐름(제어권)이 개발자(내 코드)에서 프레임워크(외부, 여기서는 스프링)로 "역전"되는 것을 뜻한다.
    - 스프링 컨테이너(프레임워크)가 객체의 생성, 초기화, 주입, 소멸 등 생명주기를 모두 책임지고 관리한다.
    - 내 코드는 "필요하다"고 선언만 하면 되고, 실제 생성 및 관리, 의존성 연결(주입)은 컨테이너가 자동으로 해줌.
    - IoC = 설계원리(철학), 구체적 구현방법 중 하나가 DI

IoC와 DI의 관계

  • IoC는 큰 원칙(제어를 외부에 위임해서 객체 생명 주기, 초기화, DI, 소멸 까지 모두 관리)
  • 그 IoC를 실제로 구현하는 대표적인 방법이 DI(Dependency Injection, 의존성 주입)
  • XML/Java 설정 등으로 수동 등록 가능

스프링에서 IoC예시

  • @Component(기본) @Service(비즈니스 로직) @Repository(DB 접근), @Controller(웹 요청 처리) 등으로 클래스 등록
  • @Autowired, 생성자 등으로 의존성 선언
  • -> 스프링이 객체를 대신 생성, 관리, 주입 = IoC 컨테이너의 역할

Spring은 왜 IoC Contatiner라고 부르는가?

단순 객체 생성기가 아니라
- 객체 생성
- 의존성 연결
- 라이프 사이클 관리
- 설정 관리
까지 다 하기 때문에

Bean 이란?

Spring Container가 관리하는 객체

Bean 생명 주기
객체생성 -> 의존성 주입 -> 초기화 -> 사용 -> 소멸

기타(DI 확장 개념)

1. Bean Scope

Bean의 생존 범위를 정의
- singleton(기본값)
- prototype
- request
- session

2. Lazy Initialization

@Lazy 실제 사용 시점에 Bean 생성 -> 초기 로딩 성능 개선

3. Qualifier

@Qulifier("beanName") 같은 타입 Bean이 여러 개일 때 구분

4.Primary

@Primary 기본 선택 Bean 지정

5.Environment/Value 주입

@Value("${spring.datasource.url}" 설정값 주입

6. Configuration & Bean 등록

@Configuration
public class AppConfig {
	@Bean
    public UserService userSrvice() {
    	return new UserService(userRepository());
      }
}        

수동 Bean 등록 방식

7. 의존성 주입 컬렉션

private List<PaymentService> paymentServices;
수동 Bean 등록 방식

필터 vs 인터셉터 vs AOP

필터(Filter), 인터셉터(Interceptor), AOP(Aspect Oriented Programming)는 다 비슷하게 "공통 기능을 여러 곳에 끼워넣는" 기술이지만, 적용 단계, 활용 목표, 구현 방식 등이 다르다.

1. 필터(Filter)

  • 역할
    - 서블릿(웹 애플리케이션) 수준에서 HTTP 요청/응답을 가장 먼저/가장 바깥에서 처리
    - 보통 인증, 인코딩 처리, 로깅, CORS같은 "웹 전체에 걸친" 전처리/후처리에 사용
  • 동작 위치
    - DispatcherServlet(=스프링 컨트롤러) 진입 전에 동작.
    - 요청 전체 흐름 조율(즉, 스프링이 아닌 "서블릿 컨테이너"단계). Dispatcher Servlet은 Spring MVC에서 프론트 컨트롤러 패턴을 구현한 핵심 컴포넌트이다.
    - 장점으로는 모든 요청을 단일 진입점에서 처리함으로서 공통 로직(보안, 로깅, 인코딩 등)을 효율적으로 관리할 수 있고, 나머지 컴포넌트들의 독립성을 유지하여 아키텍처를 유연하게 관리하는 것이 가능하다.
  • 구현 방법
    - Javax.servlet.Filter 인터페이스 구현
    - doFilter() 메소드 오버라이드
  • 예시 코드
@WebFilter(urlPatterns = "/*") 
public class MyFilter implements Filter { 
	@Override 
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
	throws IOException, ServletException { 
	// 사전 처리 
	chain.doFilter(request, response); 
	// 사후 처리 
	} 
	}

2. 인터셉터(Interceptor)

  • 역할
    - 스프링 MVC 기준에서 컨트롤러 요청 전/후를 가로채는 기술
    - 인증/인가, 로그인, 체크 URI별 권한 관리, 로깅, 세션처리 등 좀 더 "비즈니스 로직에 가까운" 영역에서 사용
  • 동작 위치
    - Filter보다 안쪽,
    - DispatcherServlet ->(인터셉터) -> 컨트롤러(Handler) -> (인터셉터) 즉, "스프링 컨텍스트 내"에서 동작
    - 구현 방법
    - HandlerInterceptor (Spring 5이상에서는)HandlerInterceptorAdapter
    - preHandle(), postHandle(), afterCompletion() 메서드 오버라이드
  • 예시 코드
public class MyInterceptor implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
	// 컨트롤러 메서드 실행 전 처리
	return true; // false면 컨트롤러 진입 X
	}
	@Override
	public void postHandle(...) {...}
	@Override
	public void afterCompletion(...) {...}
}
  • 등록은 WebMvcConfigureraddInterceptors() 오버라이드

3. AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)

  • 역할
    - 관점(Aspect)으로 "공통 관심사"를 특정 코드(메서드, 클래스 등)에 **끼워넣기(Advice)" 하는 기술
    - 트랜잭션, 로깅, 예외처리, 보안, 성능측정 등 여러 계층을 넘나드는 반복/잡무를 하나의 위치에서 처리
  • 동작 위치
    - 실제 비즈니스 메서드(Bean)의 전/후/예외 등 원하는 포인트에 동적으로 끼워넣음
    - 내부적으로는 프록시 객체 만들어서 메서드 실행 전후로 코드 삽입
    • Spring AOP 는 실제 객체를 직접 건드리는 게아니라 프록시 객체를 생성해서 그 앞뒤에 로직을 삽입한다.
  • 구현 방법
    - @Aspect 선언 + @Around,@Before,@AfterReturning,@AfterThrowing 등 어드바이스 사용
    - 핵심(비즈니스) 코드와 공통 코드 완전 분리, 매우 강력한 반복처리/로깅/보안/트랜잭션 등 전방위로 활용
  • 핵심개념
    - Aspect: 공통 로직
    • Advice: 실행 시점
    • Pointcut : 적용 위치
  • 예시 코드
@Aspect
@Component
public class LogAspect {
	@Around("execution(* com.example.service..*(..))")
	public Object log(ProcessdingJoinPoint joinPoint) thows Throwable {
	// 전
	Object result = joinPoint.proceed();
	// 후
	return result;
	}
}
구분동작 위치적용 대상구현 방법대표 활용
Filter서블릿 컨테이너요청/응답 전체javax.servlet.Filter인증,인코딩,로깅,CORS 등
Interceptor스프링 컨텍스트컨트롤러 실행 전후HandlerInterceptor로그인,권한,세션 등
AOP비즈니스 객체메소드 실행 전후 등@Aspect, 포인트컷트랜잭션,로깅,성능 등

실제 활용 예시

  • Filter: 인증서 검증, 보안 헤더 추가, 모든 HTTP 로그 남기기
  • Interceptor: 로그인 안 한 유저 접근 차단, 관리자 권한 체크, API별 로그
  • AOP: 모든 서비스 메소드 실행 시간 측정, 트랜잭션 처리, 예외 공통 로깅

요약

  • Filter: 가장 바깥에서 모든 HTTP 요청/응답을 다룸(서블릿 수준)
  • Interceptor: 스프링 컨트롤러 전후에서 더 세밀하게 다룸(비즈니스 로직 진입 직전)
  • AOP: 모든 계층의 메소드/클래스에 공통 기능을 효과적으로 주입(주로 서비스 영역, 심화 활용에 적합)

Filter vs Interceptor vs AOP 선택기준

  • 전역 HTTP 처리 -> Filter
  • URL/Controller 기준 -> Interceptor
  • 비즈니스 로직 공통 -> AOP
    범위가 넓을 수록 바깥(Filter), 좁을수록 안쪽(AOP)
profile
Rookie

0개의 댓글