Spring bean null로 뜨는 오류

김운채·2024년 9월 2일
0

Spring

목록 보기
10/10

Spring security 에서 세션을 관리하기 위해 listener 를 커스텀 하면서 listener 안의 @Autowired 한 객체 상태가 null인 현상을 만났다.

public class SecurityConfig {
	@Bean
	public ServletListenerRegistrationBean<CustomHttpSessionListener> httpSessionEventPublisher() {
		return new ServletListenerRegistrationBean<>(new CustomHttpSessionListener());
	}
}
@Component
public class CustomHttpSessionListener implements HttpSessionListener, HttpSessionIdListener {

	@Autowired
	private LogService logService;

	@Autowired
	private NotifyService notifyService;

CustomHttpSessionListener의 notifyService가 null이었던 이유는 Spring의 의존성 주입(Dependency Injection)과 빈(Bean) 생명주기와 관련이 있다.

처음 코드에서는 new CustomHttpSessionListener()로 CustomHttpSessionListener를 직접 인스턴스화하고 있다. 이렇게 하면 이 객체는 Spring의 IoC(Inversion of Control) 컨테이너에서 관리되지 않게 된다.

따라서, CustomHttpSessionListener 내부에 @Autowired로 선언된 의존성(notifyService, logService 등)이 Spring에 의해 주입되지 않기 때문에 notifyService와 logService는 null 상태가 되는 것이다.

수정된 코드

@Autowired
private CustomHttpSessionListener customHttpSessionListener;

@Bean
public ServletListenerRegistrationBean<CustomHttpSessionListener> httpSessionEventPublisher() {
    return new ServletListenerRegistrationBean<>(customHttpSessionListener);
}

이 코드에서는 @Autowired를 사용하여 CustomHttpSessionListener를 주입받고 있다. 이렇게 하면 CustomHttpSessionListener 인스턴스가 Spring에 의해 관리되며, Spring은 이 빈(Bean)을 생성할 때 logService와 notifyService와 같은 필요한 의존성을 자동으로 주입한다.

근데 @Component를 사용했는데도 왜 오류가 난걸까?

@Component를 사용하면 CustomHttpSessionListener가 Spring의 관리하에 있는 빈(Bean)으로 등록되지만, 문제는 @Component로 등록된 빈을 사용하는 방식에 있다.

첫 번째 코드에서는 @Component로 CustomHttpSessionListener를 정의했지만, SecurityConfig 클래스 내에서 직접 new CustomHttpSessionListener()로 객체를 생성하고 있다.

이렇게 직접 new 키워드를 사용하여 객체를 생성하면, 해당 객체는 Spring 컨테이너가 관리하지 않는 "일반 자바 객체"가 되는 것이다. 이 때문에 Spring이 제공하는 의존성 주입 기능(예: @Autowired)이 작동하지 않으며, 이 객체 내부의 notifyService와 logService는 null로 남게 된다.

수정된 코드에서는 @Autowired를 사용하여 CustomHttpSessionListener 빈을 SecurityConfig 클래스에 주입받고 있다. 이렇게 하면 Spring이 관리하는 빈이 그대로 주입되며, 이 빈의 의존성들도 Spring이 주입한 상태로 유지된다.

@Autowired
private CustomHttpSessionListener customHttpSessionListener;

이렇게 주입된 customHttpSessionListener는 Spring이 관리하는 빈이므로, 내부의 @Autowired 필드들도 정상적으로 주입된 상태로 사용된다.

@Component를 사용하면 CustomHttpSessionListener가 Spring의 관리하에 있는 빈(Bean)으로 등록되지만, 문제는 @Component로 등록된 빈을 사용하는 방식에 있다.

문제의 핵심
첫 번째 코드에서는 @Component로 CustomHttpSessionListener를 정의했지만, SecurityConfig 클래스 내에서 직접 new CustomHttpSessionListener()로 객체를 생성하고 있다. 이렇게 직접 new 키워드를 사용하여 객체를 생성하면, 해당 객체는 Spring 컨테이너가 관리하지 않는 "일반 자바 객체"가 된는 것이다. 이 때문에 Spring이 제공하는 의존성 주입 기능(예: @Autowired)이 작동하지 않으며, 이 객체 내부의 notifyService와 logService는 null로 남게 된다.

@Autowired를 사용한 수정된 코드의 의미
수정된 코드에서는 @Autowired를 사용하여 CustomHttpSessionListener 빈을 SecurityConfig 클래스에 주입받고 있다. 이렇게 하면 Spring이 관리하는 빈이 그대로 주입되며, 이 빈의 의존성들도 Spring이 주입한 상태로 유지된다.

@Autowired
private CustomHttpSessionListener customHttpSessionListener;

이렇게 주입된 customHttpSessionListener는 Spring이 관리하는 빈이므로, 내부의 @Autowired 필드들도 정상적으로 주입된 상태로 사용된다.

요약

  • @Component를 사용해도, 객체를 new 키워드로 생성하면 Spring이 관리하지 않는 일반 객체가 된다.
  • Spring이 관리하는 빈을 사용하려면, @Autowired 또는 다른 방법으로 Spring 컨테이너에서 빈을 가져와야 한다.
  • @Autowired로 빈을 주입받으면, 해당 빈과 그 내부의 의존성들은 모두 Spring이 관리하며, null 문제가 발생하지 않는다.

0개의 댓글