
https://howtodoinjava.com/spring-core/spring-ioc-vs-di/
스프링 DI (Dependency Injection)
Spring은 객체 간 의존관계를 프레임워크가 관리하는 IoC(Inversion of Control) 원칙에 따라 의존성을 제공한다. DI는 객체가 직접 필요한 의존 대상을 만드는 것이 아니라, 스프링 컨테이너 객체(Bean)간의 의존 관계를 외부에서 주입해주는 것을 의미한다.
이를 통해 구성(구현/생성)의 책임이 코드에서 컨테이너로 이동해, 느슨한 결합(loose coupling)을 실현할 수 있다.
- 의존성 : 어떤 객체가 동작하는데 꼭 필요한 다른 객체(예: Service에서 Repository 등).
- 주입(Injection): 이런 의존성을 개발자가 직접 new로 만드는 대신, 외부(주로 스프링 프레임워크)가 대신 만들어서(생성/관리) 넣어주는 것.
- 코드를 더 유연하게
- 개발자는 "이 객체를 어떻게 만들지"가 아니라 "이 객체가 필요하다"는 선언만 하면 됨
- 테스트 코드 작성이 쉬움
- 가짜 객체(mock,stub)를 쉽게 "주입" 해서 단위테스트 가능
- 코드 재사용, 유지보수에 강함
- 직접 생성하지 않으니 구조 바꿔도 코드 수정 최소화
- 스프링에서는 객체(Bean)의 "생명주기 관리" 까지 자동으로 해주는 "컨테이너"가 있다. DI는 여기서 자동으로 객체를 찾아서 넣어주는 기능이다.
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;
}
}
@Component @Service @Repository @Controller1. 스프링 애플리케이션 실행
2. 스프링 컨테이너가 Bean들을 자동으로 생성/등록 하고
3. 개발자가 선언한 의존성에 맞춰 DI 수행(생성자, Setter 등)의존하는 객체들을 "알아서" 주입해줌
4. 필요시(어플리케이션 종료 등) Bean 소멸 등 라이프사이클 관리도 컨테이너가 처리
@Service
public class OrderService {
private final PaymentService paymetService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService; // 스프링이 자동으로 넣어줌
}
}
OrderService가 PaymentService 를 쓴다는 "의존성"만 선언- ref: 다른 Bean(객체)을 주입
- valuse: 간단한 값(문자열, 숫자 등)주입
- 여러 의존성 객체를 List, Set, Map 형태로 한꺼번에 주입 가능
- Bean 내부에 또 다른 Bean을 선언해서 사용할 수도 있음(scope 등 다양한 설정 가능)
@Component(기본) @Service(비즈니스 로직) @Repository(DB 접근), @Controller(웹 요청 처리) 등으로 클래스 등록@Autowired, 생성자 등으로 의존성 선언단순 객체 생성기가 아니라
- 객체 생성
- 의존성 연결
- 라이프 사이클 관리
- 설정 관리
까지 다 하기 때문에
Spring Container가 관리하는 객체
객체생성 -> 의존성 주입 -> 초기화 -> 사용 -> 소멸
Bean의 생존 범위를 정의
- singleton(기본값)
- prototype
- request
- session
@Lazy 실제 사용 시점에 Bean 생성 -> 초기 로딩 성능 개선
@Qulifier("beanName") 같은 타입 Bean이 여러 개일 때 구분
@Primary 기본 선택 Bean 지정
@Value("${spring.datasource.url}" 설정값 주입
@Configuration
public class AppConfig {
@Bean
public UserService userSrvice() {
return new UserService(userRepository());
}
}
수동 Bean 등록 방식
private List<PaymentService> paymentServices;
수동 Bean 등록 방식
필터(Filter), 인터셉터(Interceptor), AOP(Aspect Oriented Programming)는 다 비슷하게 "공통 기능을 여러 곳에 끼워넣는" 기술이지만, 적용 단계, 활용 목표, 구현 방식 등이 다르다.
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);
// 사후 처리
}
}
HandlerInterceptor (Spring 5이상에서는)HandlerInterceptorAdapterpreHandle(), 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(...) {...}
}
WebMvcConfigurer의 addInterceptors() 오버라이드@Aspect 선언 + @Around,@Before,@AfterReturning,@AfterThrowing 등 어드바이스 사용@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, 포인트컷 | 트랜잭션,로깅,성능 등 |