스프링에서 어노테이션을 활용한 빈 등록 방법은 크게 2가지가 존재한다
- @Configuration + @Bean
- @Component (@Controller, @Service, @Repository)
오늘은 첫 번째 방법으로 스프링이 어떻게 빈을 등록하고 싱글톤으로 관리하는지 알아본다.
@Configuration + @Bean
스프링 컨테이너는 @Configuration
이 붙어있는 클래스를 자동으로 빈으로 등록후 해당 클래스를 파싱해서 @Bean
이 있는 메서드를 찾아 빈을 생성한다.
// 빈으로 등록할 클래스
public class MyBean {
public void sayHello() {
System.out.println("hi~!");
}
}
@Configuration
public class Config {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
이때 빈의 이름은 @Bean
이 붙은 메서드 명이 된다. 그러므로 이름이 중복되지 않도록 주의한다. 또, @Bean 어노테이션은 @Configuration 어노테이션과 함께 사용해야 싱글톤을 보장받을 수 있으므로 반드시 같이 사용해야 한다.
@Bean을 사용하여 수동으로 등록해야하는 경우는 언제일까?
- 개발자가 직접 제어가 불가능한 외부 라이브러리 사용할 때
- 애플리케이션 전범위적으로 사용되는 클래스를 등록할 때
- 다형성을 활용하여 여러 구현체를 등록해주어야 할 때
Singleton을 지키는 매커니즘
그렇다면 스프링은 어떠한 원리로 Singleton을 지킬수 있는 걸까? 아래의 코드를 살펴보자.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
위의 코드에서 memberService 빈 생성시 new MemoryRepository()를 호출하고, orderService의 빈에서도 마찬가지로 new MemoryRepository()를 호출한다. new로 생성되므로 서로 다른 인스턴스로 생각될 것이다.
그러나 스프링에서는 클래스에 @Configuration 어노테이션이 붙어있는 경우, 바이트코드를 조작하는 라이브러리를 사용하여 싱글톤으로 관리한다.
아래의 코드를 실행하면,
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean.getClass() = " + bean.getClass());
}
CGLIB
바이트 코드를 가지고 프록시 객체를 만들어주는 라이브러리. 런타임 시 자바 클래스를 상속하고 인터페이스를 구현해 동적 프록시 객체를 만든다. 즉, proxyBeanMethods가 true인 상태에서 사용되는 config 빈은 CGLIB 라이브러리에서 생성해준 프록시 객체임을 의미한다.
Configuration의 속성 중 proxyBeanMethods가 빈을 싱글톤으로 관리하는 것과 연관이 있는 속성이다. 디폴트 값으로 true를 가지고 있어 빈에 대한 프록시 객체가 생성된다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
boolean proxyBeanMethods() default true;
boolean enforceUniqueMethods() default true;
}
정리
스프링은 싱글톤 타입인 빈을 만들기 위해 프록시 객체를 생성한다. Configuration 클래스를 그대로 사용하는 것이 아닌, 이를 상속한 프록시 객체를 새로 만들어 관리한다. 수동등록시 반드시 @Configuration 어노테이션과 @Bean 어노테이션을 같이 사용해야 싱글톤을 보장받을 수 있으므로 같이 사용해야 한다.
외부에서 구현한 클래스를 빈으로 등록시에는 @Component 어노테이션을 사용할 수 없다. 이때 @Configuration을 사용하여 메서드 내부에서 해당 클래스를 호출하여 반환하고 빈으로 등록할 수 있다.
https://devmoony.tistory.com/192
https://velog.io/@leesomyoung/SpringBoot-빈-등록을-위한-Configuration-Bean-Component
https://tecoble.techcourse.co.kr/post/2023-05-22-configuration
https://velog.io/@max9106/Spring-Configuration을-통한-빈-등록-시-싱글톤-관리
'Backend > Spring' 카테고리의 다른 글
[Spring] 리플렉션(Reflaction)이란? 생성자 주입은 빈 생성때의 리플렉션 외에 추가적인 리플렉션을 진행하는가? (0) | 2024.01.02 |
---|---|
[Spring] 의존성 주입(Dependency Injection) 4가지 방법 (0) | 2023.12.29 |
[Spring] 스프링 입문 - 코드로 배우는 스프링 부트 #4 스프링 빈과 의존관계 (0) | 2023.11.21 |
[Spring] 스프링 입문 - 코드로 배우는 스프링 부트 #3 회원 관리 예제(백엔드) (0) | 2023.09.12 |
[Spring] 스프링 입문 - 코드로 배우는 스프링 부트 #2 (0) | 2023.08.31 |