엔지니어로 가는 길

@Bean을 통한 빈 등록시 주의해야 할 점 본문

프로그래밍/Spring

@Bean을 통한 빈 등록시 주의해야 할 점

탐p슨 2021. 5. 17. 18:10
728x90

많은 경우 component scan을 통해서 자동으로 빈 등록이 이루어지지만 때로는 직접 @Bean 어노테이션을 통해 빈으로 등록해야할 때가 있다. @Bean 어노테이션을 통해 빈으로 등록할 때 주의해야 할 점에 대해 살펴본다.

 

@Configuration 클래스와 @Bean

먼저 @Configuration 어노테이션이 붙은 설정 전용 클래스 안에서 @Bean 어노테이션을 통해 빈으로 등록하는 경우이다.

 

 

@Bean이 붙은 메소드는 기본적으로 싱글톤이기 때문에 여러 번 호출돼도 하나의 객체만 리턴되는 것이 보장된다. 보통의 클래스라면 메소드가 이렇게 동작하지 않는다. 정직하게 작성된 대로 동작한다. 코드가 new MyBean()이라고 적혀 있으면, 호출될 때마다 객체가 생성된다. 따라서 @Configuration과 @Bean을 사용하는 클래스는 순수한 객체 팩토리 클래스라기보다는 자바 코드로 표현되는 메타정보라고 이해하는 것이 좋다.

 

POJO와 @Bean

@Configuration이 붙은 클래스가 아닌 POJO 클래스에서도 @Bean을 사용할 수 있다. 이 경우에도 @Bean은 동일하게 새로운 빈을 정의하는 설정 메타정보로 사용되고, 그 리턴 오브젝트가 빈 오브젝트가 된다. 물론 @Bean 메소드를 가진 클래스는 어떤 방법으로든지 빈으로 등록돼야 한다. (@Configuration이 붙은 클래스는 @Configuration에 의해 빈으로 등록된다.) @Configuration이 붙지 않았다는 건 클래스 자신이 평범한 빈으로 사용되도록 만들어졌다는 의미다.

 

POJO에 @Bean 메소드를 이용한 빈 메타정보 선언 기능을 사용해야 할 때는 언제일까? 일반적으로 @Bean 메소드를 통해 정의되는 빈이 클래스로 만들어지는 빈과 매우 밀접한 관계가 있는 경우, 특별히 종속적인 빈인 경우 사용할 수 있다. 하지만 설정정보가 일반 애플리케이션 코드와 함께 존재하기 때문에 유연성이 떨어진다는 단점이 있다. @Configuration은 비록 자바 코드이긴 하지만 그 자체로 독립적인 설정정보이기 때문에 분리가 가능하지만, 일반 빈 클래스의 @Bean에 담긴 설정정보는 수정을 위해 빈 클래스를 직접 수정해야 한다는 불편이 뒤따른다.

 

 

앞에서 “빈은 기본적으로 싱글톤이기 때문에 @Bean이 붙은 메소드는 여러 번 호출돼도 하나의 오브젝트만 리턴되는 것이 보장된다”고 했지만 이는 @Configuration 클래스 안에서 사용된 @Bean 메소드에만 해당된다. 일반 POJO 클래스 안에서 사용된 @Bean 메소드는 매번 다른 오브젝트를 리턴한다. 그래서 POJO 안에서 DI 설정을 위해 다른 @Bean 메소드를 직접 호출하면 매번 다른 오브젝트를 받게된다. 테스트해보자.

 

 

인텔리제이가 벌써 경고를 띄워주고 있다.

 

 

@Bean이 붙은 메소드를 직접호출하지 말고 클래스에서 해당 빈을 DI 받은 뒤 사용하라는 뜻인 것 같다. (자기 자신이 만든 빈을 DI 받는다는 게 어색해보이지만 문제될 것은 없다.) 똑같은 코드를 일반 클래스가 아니라 @Configuration이 붙은 클래스에서 쓰면 경고는 사라진다. @Configuration이 붙은 클래스에서 @Bean 메소드는 기본적으로 매번 같은 객체를 리턴하기 때문이다.

 

 

테스트는 간단하게 ApplicationRunner의 구현체에 만들어보았다. MyBean2 객체의 MyBean과 MyBean3 객체의 MyBean이 동일한 객체인지 검증하는 테스트이다. 인텔리제이가 보여줬던 이전의 경고는 모른척하고 실행해보자. 빨간 밑줄이 떴지만 컴파일 에러가 아니라 일종의 경고이기 때문에 무시하고 실행할 수 있다.

 

 

MyBean이 싱글톤이라면, IMPOJO의 myBean 메소드가 호출될 때마다 같은 객체를 리턴했다면 MyBean2에 들어있는 MyBean 객체와 MyBean3에 들어있는 MyBean 객체는 동일해야 한다. 하지만 테스트 결과 동일하지 않음이 증명되었다. 인텔리제이가 알려준 대로 코드를 수정해보자.

 

 

 

먼저 MyBean을 DI받은 뒤, DI받은 것을 사용하고 있다. 이렇게 코드를 수정하고 같은 테스트를 실행하면 테스트에 성공한다.

 

참고: 토비의 스프링 3.1 vol.2

728x90
Comments