해결된 질문
작성
·
150
2
기존 스프링 빈 방식으로 등록을 하면 등록해야 할 스프링 빈이 수십,수백개가 되어 일일이 등록하기가 귀찮고, 설정 정보도 커지고 누락하는 문제가 발생하여 컴포넌트 방식을 사용한다고 배웠습니다. 그런데 컴포넌트 방식도 사용하려고 하면 @Component와 의존 관계 주입인 @Autowired를 넣어줘야 하는데, 동일한 문제가 발생하는게 아닌지 궁금합니다.
2.excludeFilters로 @Configuration 어노테이션이 붙은 클래스를 제거해주고 있는데, 앞서 정의했던 AppConfig 때문인가요? 만약 AppConfig가 없다고 가정하면 excludeFilters를 굳이 삽입하지 않아도 되는지 궁금합니다.
@Autowired 과정이 getBean(MemberRepository.class)와 동일하다고 하는데, 이해가 가지 않습니다.
필터 부분 코드가 전체적으로 이해가 가지 않습니다.
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
여기서 target,retention,documented가 어떤 역할을 하는건가요?
package hello.core.scan.filter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.context.annotation.ComponentScan.Filter;
public class ComponentFilterAppConfigTest {
@Test
void filterScan() {
ApplicationContext ac = new
AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
assertThat(beanA).isNotNull();
Assertions.assertThrows(
NoSuchBeanDefinitionException.class,
() -> ac.getBean("beanB", BeanB.class));
}
@Configuration
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
static class ComponentFilterAppConfig {
}
}
여기서도 beanA가 왜 추가되고, beanB가 왜 포함되지 않는지 궁금합니다.
답변 1
1
안녕하세요. 이준승님
1. 기존 스프링 빈 방식으로 등록을 하면 등록해야 할 스프링 빈이 수십,수백개가 되어 일일이 등록하기가 귀찮고, 설정 정보도 커지고 누락하는 문제가 발생하여 컴포넌트 방식을 사용한다고 배웠습니다. 그런데 컴포넌트 방식도 사용하려고 하면 @Component와 의존 관계 주입인 @Autowired를 넣어줘야 하는데, 동일한 문제가 발생하는게 아닌지 궁금합니다.
-> @Bean으로 하나하나 빈을 등록하는 것과 @Component를 사용하는 것은 코드 양에 있어서 매우 큰 차이가 있습니다. 내가 만든 클래스에 간단히 @Component만 넣어주면 되기 때문에 매우 단순합니다. 추가로 @Autowired는 강의에서 설명드린 것 처럼 생성자 주입의 경우 생략할 수 있습니다.
2.excludeFilters로 @Configuration 어노테이션이 붙은 클래스를 제거해주고 있는데, 앞서 정의했던 AppConfig 때문인가요? 만약 AppConfig가 없다고 가정하면 excludeFilters를 굳이 삽입하지 않아도 되는지 궁금합니다.
-> 네 맞습니다. 다른 @Configuration이 없다면 제거해도 됩니다.
3. 답변: @Autowired는 결과적으로 스프링 컨테이너에서 스프링 빈을 찾아서 주입하게 됩니다. 이 과정에서 내부적으로 getBean(MemberRepsotiroy.class)를 실제로 호출하게 됩니다. 이런 과정을 편리하게 만들어 주는 것이 @Aurowired 입니다.
4. target,retention,documented는 자바가 제공하는 기본 애노테이션입니다. 애노테이션을 만들 때 필요합니다.
-> 사실 이 부분은 크게 중요하지는 않습니다 :) 그냥 이렇구나 정도 하고 넘어가셔도 충분합니다 🙂
@Target(ElementType.TYPE): 이 메타-애너테이션은 MyIncludeComponent 애너테이션을 어디에 적용할 수 있는지를 정의합니다. ElementType.TYPE는 이 애너테이션을 클래스, 인터페이스, 열거형, 또는 어노테이션 타입에 적용할 수 있음을 의미합니다.
@Retention(RetentionPolicy.RUNTIME): 이 메타-애너테이션은 MyIncludeComponent 애너테이션이 어떻게 유지되는지를 정의합니다. RetentionPolicy.RUNTIME은 런타임 동안에도 이 애너테이션이 유지되며, 리플렉션(Reflection)을 통해 접근할 수 있음을 나타냅니다.
@Documented: 이 메타-애너테이션은 MyIncludeComponent 애너테이션이 문서화되어야 함을 나타냅니다. 즉, 이 애너테이션이 사용된 요소에 대한 문서를 생성할 때, MyIncludeComponent 애너테이션 정보도 문서에 포함됩니다.
5. 여기서도 beanA가 왜 추가되고, beanB가 왜 포함되지 않는지 궁금합니다.
-> AnnotationConfigApplicationContext를 통해서 스프링 컨테이너를 만들 때 기본 설정 파일로 ComponentFilterAppConfig.class를 사용합니다. 이 클래스는 MyIncludeComponent.class는 애노테이션이 있으면 컴포넌트 스캔에서 포함하고, MyExcludeComponent.class 애노테이션이 있으면 컴포넌트 스캔에서 제외합니다.
컴포넌트 스캔 대상에 추가할 클래스
@MyIncludeComponent
public class BeanA {
}
컴포넌트 스캔 대상에서 제외할 클래스
@MyExcludeComponent
public class BeanB {
}
따라서 BeanA만 스프링 컨테이너에 등록됩니다.
감사합니다.