스프링 빈을 등록하는 방법으로 @Configuration, @Component, @Bean이 있습니다.
이러한 어노테이션에 대해서 알아보겠습니다.
1. @Configuration 어노테이션
빈을 수동으로 등록하기 위해서 @Bean 어노테이션을 사용합니다. 보통 수동으로 여러 개 등록하는 경우 @Configuration 어노테이션과 함께 사용합니다. 메소드 이름을 갖고 빈 이름이 결정되기 때문에 중복된 이름으로 빈을 생성하지 않도록 주의합니다.
@Bean 어노테이션은 수동으로 등록해 주어야 하는데, 특히 개발자가 직접 제어 불가능한 라이브러리를 활용하고자 할 때 사용합니다. 1개의 객체만 생성하여 여러 클래스가 사용함으로써 메모리를 아낄 수 있다는 장점이 있습니다.
동작방식
1. @Configuration은 @Component 어노테이션을 가지고 있기 때문에 컴포넌트 스캔에 의해 bean 으로 등록됩니다.
2. @Configuration 어노테이션이 붙어있는 클래스를 파싱해서 @Bean이 있는 메소드를 찾습니다.
3. 해당 메소드에 있는 생성자를 실행하여 반환된 객체를 메소드 명으로 하여 bean으로 등록합니다.
예제
@Configuration
public class TestConfiguration {
@Bean
public TestInfo testInfo1() {
return new TestInfo("myTestBean1");
}
@Bean(name = "testInfo2")
public TestInfo testInfo2() {
return new TestInfo("myTestBean2");
}
}
@Configuration 어노테이션 선언 후 @Bean을 적용하였습니다. 실행 시 Component Scan에 의해 TestConfiguration을 bean으로 등록 후 파싱 후에 'testInfo1' / 'testInfo2' 메소드 2개의 bean이 등록됩니다.
아래와 같이 DI를 통해 사용할 수 있습니다.
@Slf4j
@Service
public class TestService1 {
private final TestInfo testInfo1;
private final TestInfo testInfo3;
public TestService1(TestInfo testInfo1,
@Qualifier(value = "testInfo2") TestInfo testInfo3) {
this.testInfo1 = testInfo1;
this.testInfo3 = testInfo3;
}
}
bean의 이름은 변수명과 맞추어서 생성이 됩니다.
만약 bean을 직접 지정하고 싶다면 @Qualifier 어노테이션을 이용하면 주입할 bean을 설정할 수 있습니다.
testInfo가 싱글톤 bean으로 등록 되어 1개의 객체만 생성합니다.
이는 여러 클래스가 하나의 객체를 공유하기 때문에 같은 주소를 출력합니다.
2. @Component 어노테이션
메소드 단위로 수동으로 등록하는 @Bean 어노테이션과 다르게 @Component는 클래스 단위로 등록하며
해당 어노테이션이 붙은 클래스는 Component Scan의 대상이 되어 bean으로 등록됩니다.
수동이 아닌 자동으로 등록되기 때문에 직접 클래스를 짜고 이를 bean으로 등록할 때에 효과적인 방식입니다.
예제
@Component
public class TestComponent {
private String name;
private Integer age;
public TestComponent() {
}
@Builder
public TestComponent(String name, Integer age) {
this.name = name;
this.age = age;
}
}
클래스 생성 후 위에 @Component 어노테이션을 붙여줍니다.
Component scan이 진행되면서 해당 클래스를 bean으로 등록합니다.
마찬가지로 DI를 통해 객체를 bean으로 등록할 수 있습니다.
@Slf4j
@Service
public class TestService1 {
private final TestComponent testComponent;
public TestService1(TestComponent testComponent) {
this.testComponent = testComponent;
}
}
마찬가지로 다른 클래스에서 해당 Component를 DI하더라도 생성된 객체를 가져다 쓰는 것을 볼 수 있습니다.
3. @Component / @Bean 차이
@Component
- Component Scan을 통해 자동으로 탐지되어 Bean으로 등록됩니다.
- 개발자가 직접 컨트롤이 가능한 클래스 혹은 인터페이스 단위에 붙여 사용합니다.
@Bean
- 개발자가 제어 불가능한 외부 라이브러리들을 Bean으로 등록할 때 사용합니다.
외부 라이브러리 클래스에 직접 @Component를 밀어 넣어줄 수 없기 때문입니다. - 메소드 단위로 붙여 등록이 가능하며 외부 라이브러리의 생성자를 return 되게 하면
스프링에서는 이를 이용하여 생성된 객체를 bean으로 등록합니다.
4. @Configuration + @Bean ?
@Configuration을 붙이게 되면 스프링이 CGLIB으로 바이트 코드를 조작합니다.
이를 통해 싱글톤 패턴이 적용되어 인스턴스가 1개만 생성되도록 바이트 코드가 조작이 되고, 프록시 객체가 생성됩니다.
CGLIB이란 Code Generator Library 로써 런타임에 동적으로 자바 클래스에 대해 프록시를 생성해 주는 기능입니다.
@Test
@DisplayName("01. test")
@Order(1)
public void 테스트() throws Exception {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfiguration.class);
TestConfiguration bean = ac.getBean(TestConfiguration.class);
}
바이트 코드가 조작된 프록시 객체는 끝에 CGLIB으로 시작하는 것을 볼 수 있습니다.
결국, @Bean을 이용하여 bean들을 수동 등록할 때
@Configuration을 이용해서 인스턴스가 1개만 생성될 수 있도록 싱글톤 패턴을 적용하기 위함입니다.
하지만 @Component 어노테이션을 지정하면 Lite Mode로 동작하여 코드가 수행됩니다.
5. @Bean + @Configuration 대신 @Bean + @Component를 사용하면 ?
스프링에서 기본적으로 생성되는 bean은 프록시 빈입니다.
하지만 @Configuration 대신 @Component를 붙인다면 Lite Mode Bean이 생성됩니다.
Lite Mode Bean은 CGLIB을 사용하여 바이트코드를 조작하지 않는다는 특징이 있습니다.
예제
@Component
public class TestConfiguration {
@Bean
public TestInfo testInfo1() {
return new TestInfo("myTestBean1");
}
@Bean
public TestInfo anyTestInfo() {
return testInfo1();
}
}
Configuration 파일에서 @Configuration -> @Component로 교체하였습니다.
이 경우 Lite mode bean이 생성되며 Proxy bean이 아니기 때문에 새로운 객체가 생성되는 것을 볼 수 있습니다.
결론적으로 바이트 코드가 수정된 프록시 객체가 아니므로 싱글톤 패턴 적용이 되어있지 않습니다.
다음 결과는 @Component가 아닌 @Configuration을 적용한 결과입니다. 객체를 여러 번 생성해도 하나의 인스턴스만 만들어져 주소가 같은 것을 볼 수 있습니다.
Proxy bean은 Lite mode bean보다 생성 속도가 느립니다. 하지만 스프링 기능(ex) AOP) 사용에는 제한이 있으므로 일반적으로는 Proxy bean을 생성합니다.
혹시나 잘못된 부분이 있다면 지적 감사드립니다.
6. 참고
[1] https://stackoverflow.com/questions/10604298/spring-component-versus-bean
Spring: @Component versus @Bean
I understand that @Component annotation was introduced in spring 2.5 in order to get rid of xml bean definition by using classpath scanning. @Bean was introduced in spring 3.0 and can be used with @
stackoverflow.com
Spring @Component Annotation | Baeldung
Learn about the Spring @Component annotation.
www.baeldung.com
[3] https://hyojabal.tistory.com/25
Lite Mode Bean
Spring Bean 의 Lite Mode 가 있다. Lite mode 라 함은 Cglib 를 사용하여 바이트 코드 조작을 하지 않음을 의미한다. @Configuration 어노테이션을 지정하게 되면 Cglib가 사용되며 메서드 호출은 모두 1회만 일..
hyojabal.tistory.com
[4] https://multifrontgarden.tistory.com/253
spring bean lite mode
spring bean 설정시 lite mode 라는게 있어서 찾아보고, 그에대해 정리해보려한다. 일단 lite mode 는 java 설정에서만 사용할 수 있다. 보통의 java 설정파일을 알아보자. @Configuration public class BeanConfi..
multifrontgarden.tistory.com
'Spring' 카테고리의 다른 글
Spring Boot + Nuxt.js 환경에서의 FCM 웹 푸시 구현 (1/2) - Spring Boot편 (0) | 2023.04.15 |
---|---|
[Mybatis] Mybatis에서 DTO로 분리하기 (0) | 2023.03.16 |
@Transactional Annotation 정리 (0) | 2022.09.13 |
세션 vs JWT (0) | 2022.06.21 |
Spring Boot Rest API 이메일 인증 (2) | 2021.11.10 |