스프링 IoC/DI 부먹

2025. 3. 10. 18:31BackEnd(Java)/Spring Boot

✅ 아래 내용들에 대해서 알아보자

- 스프링 컨테이너로 빈 관리를 안 하면?

 

1편에 이어서..

 

스프링 컨테이너로 빈 관리를 안 하면?

스프링 컨테이너(Bean Factory 또는 ApplicationContext)에 등록된 빈(Bean)은 스프링의 생명주기 관리, 의존성 주입, 프락시 생성 등을 통해 다양한 기능을 활용할 수 있습니다. 반면, new로 생성한 객체는 스프링의 관리 범위 밖에 있으므로 아래와 같은 기능을 사용할 수 없습니다.

 

 

1. AOP (Aspect-Oriented Programming)

스프링의 AOP는 주로 프록시 패턴을 통해 구현됩니다. @Transactional, @Around, @Before 같은 AOP 기능은 스프링이 빈을 프록시 객체로 감싸서 제공합니다.

 
@TransactionalEventListener, @Async, @Transactional, @Cacheable, @CachePut, @CacheEvict, @Retryable 등 같은 어노테이션은 프록시를 통해 동작한다.
 

 @TransactionalEventListener

  • 동작:
    • @TransactionalEventListener는 트랜잭션 상태(예: AFTER_COMMIT)에 따라 이벤트 처리를 지연시키거나 조건부로 실행합니다.
    • 이를 위해 Spring은 트랜잭션 동기화 매니저(TransactionSynchronizationManager)와 연계하며, 메서드 호출을 프록시로 래핑합니다.
  • 프록시 사용:
    • @TransactionalEventListener가 붙은 메서드는 Spring AOP 프록시를 통해 트랜잭션 상태를 감지하고, 적절한 시점에 호출됩니다.
    • 따라서 프록시 기반이라고 할 수 있습니다.

 

 @Async

  • 동작:
    • @Async가 붙으면 메서드가 별도 스레드에서 비동기적으로 실행됩니다.
    • Spring은 이를 위해 프록시를 생성해 비동기 호출을 처리합니다.
  • 프록시 사용:
    • @Async는 AOP 프록시를 통해 메서드 호출을 인터셉트하고, TaskExecutor로 작업을 위임합니다.

 

자기 참조 문제와 프록시

  • 문제:
    • 동일 클래스 내에서 @EventListener 메서드가 다른 @EventListener 메서드에서 발행된 이벤트를 처리하려면, Spring의 프록시를 거쳐야 합니다.
    • 하지만 같은 객체 내에서 직접 메서드를 호출하면 프록시가 우회되어 @EventListener가 동작하지 않습니다.
    • @Transcational 어노테이션도 동일함.
  • 이유:
    • Spring AOP는 프록시 기반으로 동작하며, 프록시는 빈 간 호출에서만 적용됩니다.
    • 클래스 내부 호출(this.handleAnotherMethod())은 프록시를 거치지 않으므로 어노테이션(@Async, @Transactional 등)이 무시됩니다.

 

 

 

 

2. 트랜잭션 관리

트랜잭션 매니저(PlatformTransactionManager)는 스프링 빈에만 적용된다.

@Transactional은 AOP를 통해 트랜잭션 시작/커밋/롤백을 처리하므로, 스프링 DI로 관리되지 않는 객체에서는 동작하지 않습니다.

 

new로 생성한 객체는 데이터베이스 작업을 트랜잭션 없이 실행하거나, 호출 스택 상위의 트랜잭션에 의존하게 됩니다.

트랜잭션 전파도 타지않게 된다.

 

 

3. 의존성 주입 (DI)

@Autowired, @Inject 같은 의존성 주입은 스프링 컨테이너가 빈 간의 관계를 관리할 때만 동작합니다. 내부 필드에 @Autowired가 있어도 주입되지 않고 null로 남습니다.

 

 

4. 생명주기 관리

스프링은 빈의 생성(@PostConstruct), 소멸(@PreDestroy), 초기화 등을 관리합니다. new로 생성한 객체는 이러한 생명주기 콜백이 호출되지 않습니다.

 

 

5. 이벤트 처리

스프링의 이벤트 시스템(ApplicationEventPublisher, @EventListener)은 빈 간의 통신을 지원합니다. 스프링 DI로 관리되지 않는 객체는 이벤트를 발행하거나 수신할 수 없습니다.

 

6. 환경 설정 및 프로퍼티 주입

@Value로 환경 변수나 프로퍼티 파일 값을 주입받는 기능은 빈에만 적용됩니다. 스프링 DI로 관리되지 않는 객체는 @Value가 무시되어 기본값이나 null이 사용됩니다.

 

 

7. 캐싱 (@Cacheable, @CacheEvict)

스프링의 캐싱 추상화는 AOP를 통해 구현됩니다. 스프링 DI로 관리되지 않는 객체는 캐싱이 적용되지 않습니다.

 

 

8. 보안 (@PreAuthorize, @Secured)

스프링 시큐리티의 메서드 수준 보안도 AOP 기반입니다. 스프링 DI로 관리되지 않는 객체는 보안 설정이 무시됩니다.

 

 

결론

 

 스프링의 DI로 관리되지 않는 객체는 스프링 내부 아키텍처(특히 AOP, 트랜잭션, 의존성 주입 등)를 활용할 수 없다. 왜냐하면 스프링이 프록시와 컨테이너를 통해 기능을 제공하는 방식 때문입니다.

반응형