์ปดํฌ๋ํธ ์ค์บ๊น์ง ์ด์ฐ์ ์ฐ ์๋ค. ์ฌ์ค ๋ธ๋ก๊ทธ ์ ๋ฆฌ๋ง ์๋์์ด๋ ๊ฐ์๋ ํ๋ฌ ์์ ๋๋์ ๋ฏ... ๊ทธ๋๋ ๋ธ๋ก๊ทธ ์ ๋ฆฌํ๋ฉด์ ํ์ ๊ทธ๋ฅ ๋๊ฒผ์ ์ง๋ฌธ๋ค ๋ชฝ๋ ์ฐพ์๋ณด๋ ์ค์ด๋ค. ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ์ง๋ง ๊ทธ๋งํผ ๋ด ๋จธ๋ฆฌ์ ์ง์๋ ํ๋ ๋ ์ฑ์์ง๊ณ ์์์ ๋๋๋ค. (์ฌ์ค ๋ธ๋ก๊ทธ ์ ๋ฆฌ์ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ ค ํํ์์ ์ฃผ์ ์ฃผ์ ์ ์ด๋ณธ๋ค) ์ด๋ฒ ์น์ 6์ ๊ฐ์๊ฐ ์งง์์ ๋นจ๋ฆฌ ๋๋ ์ง๋ ๋ชจ๋ฅธ๋ค๋ ๊ธฐ๋๊ฐ์ด ์๋ค. ์ฐ๋ฆฌ์ง ์์ด์ปจ ๊ณ ์ฅ๋์ ์๋์ค์ง๋ง,,,๐ฅฒ ๋์ ์ด๊ฒจ๋ด๊ณ ! ๋ชจ๋๋ค ํ์ดํ !!!
๐งธ
๐งธ ๊ตฌ์กฐํ์ ๋ ์ธ ๊ผฌ์ฐ- ๐งธ
- main
ใด class : AutoAppConfig - test - scan
ใด class : AutoAppConfigTest - test - scan - filter
ใด class : BeanA, BeanB, ComponentFilterAppConfigTest
ใด Annotation : MyExcludeComponent, MyIncludeComponent
Q. ์ปดํฌ๋ํธ ์ค์บ์ด๋?
A. ์ค์ ์ ๋ณด๊ฐ ์์ด๋ ์๋์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ค.
โ๏ธ AutoAppConfig
์ปดํฌ๋ํธ ์ค์บ ์ค์
@ComponentScan(
basePackages = "hello.core.member",
basePackageClasses = AutoAppConfig.class,
excludeFilters = @ComponentScan.Filter
(type = FilterType.ANNOTATION, classes = Configuration.class)
)
@ComponentScan
: @Component์ด๋ ธํ ์ด์ ๋ฐ streotype(@Service, @Repository, @Controller.)์ด๋ ธํ ์ด์ ์ด ๋ถ์ฌ๋ ํด๋์ค๋ค์ ์๋์ผ๋ก Scanํ์ฌ Bean์ผ๋ก ๋ฑ๋กํด์ฃผ๋ ์ญํ ์ ํ๋ ์ด๋ ธํ ์ด์ ์ด๋ค.
basePackages
: String์ผ๋ก ์ ๋ ฅ๋ ํจ์บ์ง์ ๊ฒฝ๋ก๋ฅผ ์ค์บํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ง์ ์ค์บํ ์์น๋ฅผ ์ง์ ํ๋ค.
basePackageClasses
: ์ ํ ํด๋์ค๊ฐ(ํจํค์ง ์) ์์นํ ๊ณณ๋ถํฐ ๋ชจ๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ๋ ํด๋์ค๋ฅผ bean์ผ๋ก ๋ฑ๋กํด์ค๋ค.
excludeFilters
: ๊ฐ์ฒด๋ฅผ ์ ์ธํ๋ค. (AppConfig์ ์๋์ผ๋ก ๋ฑ๋กํ ๊ฒ๋ค์ ๋นผ์ค๋ค)
includeFilters
: @Component ์ด๋ ธํ ์ด์ ์ด ์ฌ์ฉ๋ ๊ฐ์ฒด๋ฅผ ๋ถ๋ฌ์ค๊ณ ์ถ์ผ๋ฉด, includeFilters ์ค์ ์ ์ฌ์ฉํ๋ค. ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ํด๋์ค๋ง์ ์ค์บํ๋๋ก ์ง์ ํ๋ค.
Q. basePackages๋ณด๋ค basePackagesClasses๋ฅผ ์ฐ๋๊ฑธ ๊ถ์ฅํ๋ค. ์ ๊ทธ๋ฐ ๊ฒ์ผ๊น?
A. ์ปดํฌ๋ํธ ์ค์บ์ด ์ด๋ป๊ฒ ๋์ํ๋์ง ์ดํดํด์ผํ๋ค. ์ปจํฌ๋ํธ ์ค์บ์ ํ๋ ค๋ฉด @SpringBootApplication์ ์ดํด๋ด์ผํ๋ค. @SpringBootApplication์๋ @ComponentScan์ ๊ฐ์ง๊ณ ์๊ณ @ComponentScan์ ๊ฐ์ง๊ณ ์๋ ์ด๋ ธํ ์ด์ ์ด ์์์ง์ ์ด๋ค. @ComponentScan์ ๋ถ์ด๊ณ ์๋ ๊ทธ ํด๋์ค๋ถํฐ ์ปดํฌ๋ํธ ์ค์บ์ ์์ํ๋ค. ์ค์ ํด ๋์ ํจํค์ง๋ค ์ค์์, ํด๋น ํจํค์ง์ ํ์ ํจํค์ง์ ๋ํด์ @Component ๊ฐ์ ์คํ ๋ ์ค ํ์ ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํด๋์ค๋ฅผ ๋ชจ๋ ์ฐพ์์ ๋น์ผ๋ก ๋ฑ๋กํ๋ค. ๊ทธ๋ฌ๋๊น ์ด๋ฐ์์ผ๋ก ๊ฐ๋๊ฒ spring์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ์ ์ธ ๊ฒฝ๋ก์ธ ๊ฒ ๊ฐ๋ค. ๊ทธ๋ฐ๋ฐ basePackages๋ ๋ด๊ฐ ์ง์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ๊ฒ์ผ๋ก springboot์์ ์ ๊ณต๋๋ ์ต์์ ํจํค์ง๋ถํฐ ์์ํ์ง ์๊ฒ๋๋ค๋ ๊ฒ์ด๋ค. springboot์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ํจ์จ์ ์ด๊ณ ํฅํ ํ๋ก์ ํธ๊ฐ ์ปค์ง์ ๋ฐ๋ผ ๋ณต์ก์ฑ์ ์ค์ฌ์ค๋ค.
- basePackage๋ฅผ ๊ถ์ฅํ์ง ์๋ ์ด์ ์ถ์ฒ
••• ์ด์ด์ ๋ค๋ฅธ ์ฝ๋ ๋ถ๋ถ •••
public class AutoAppConfig {
}
ํ์ฌ AutoAppConfig ํด๋์ค์ ์ญํ ์ ์ปดํฌ๋ํธ ์ค์บ์ ์ค์ ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋ฉ์๋๋ ๋ค๋ฅธ ์ฝ๋๋ ์ ์ง ์๋๋ค.
โ๏ธ OrderServiceImpl
์์กด๊ด๊ณ์๋์ฃผ์
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
@Component
: @Component ์ด๋ ธํ ์ด์ ์ ์ด์ฉํ๋ฉด Bean Configuration ํ์ผ์ Bean์ ๋ฐ๋ก ๋ฑ๋กํ์ง ์์๋ ์ฌ์ฉํ ์ ์๋ค.
@Autowired
: ์์ฑ์์์ ์ฌ๋ฌ ์์กด๊ด๊ณ๋ ํ๋ฒ์ ์ฃผ์ ๋ฐ์ ์ ์๋ค.
• @Component
: Bean ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ผ๋ฉฐ(์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉ), IoC์ปจํ ์ด๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์๋์ผ๋ก ๊ฐ์ฒด ์์ฑ๋๋ฉด Sigleton์ด๋ค.
• @Controller
: ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ์ ์ฌ์ฉํ๋ฉฐ, Dispatcher(HTTPํ๋กํ ์ฝ๋ก ๋ค์ด์จ ์์ฒญ์ ๋ฐ์ ์ ํฉํ ์ปจํธ๋กค๋ฌ์๊ฒ ์์)์ @Controller๊ฐ ์๋ ํด๋์ค๋ค์ ํ์ธํด์ @RequestMapping์ด ์๋ ๋ฉ์๋๋ค์ ํ์ธํฉํ์ฌ ์์ฒญ์ ์ฒ๋ฆฌํ๋ค.
• @Service
: ๋น์ง๋์ค ๋ก์ง์ ์์ผ๋ฉฐ ์ ์ฅ์ ๊ณ์ธต์ ์ฌ์ฉํ๋ค.
• @Repository
: ๋ฐ์ดํฐ ์์ธ์ค ๊ณ์ธต์์ ์ฌ์ฉํ๋ค. ์ฃผ๋ก ์ปดํฌ๋๋ ์ค์บ ๋์์ด ๋๊ธฐ ์ํด ์ฌ์ฉํ์ง๋ง, ์คํ๋ง๋ถํธ์ JPA๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ์์ธ ๋ณํ๊ธฐ๋ฅผ ์๋์ผ๋ก ๋ฑ๋กํด์ @Repository๋ฅผ ์ ์ฉํ ๋น์ ํ๋ก์๋ก ๋ณํํ๋ค.
• @Configuration
: ์ค์ ํ์ผ์ ๋ง๋ค๊ธฐ ์ํ, Bean์ ๋ฑ๋กํ๊ธฐ ์ํ ์ ๋ ธํ ์ด์ ์ด๋ค. ์ฑ๊ธํค์ ์ ์งํ๋๋ก ์ถ๊ฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ค.
- @Controller, @Service ์ถ์ฒ
โ๏ธ AutoAppConfigTest
์ปดํฌ๋ํธ ์ค์บ์ด ์ ์๋๋๋์ง ํ์ธ
@Test
void basicScan() {
AnnotationConfigApplicationContext ac
= new AnnotationConfigApplicationContext(AutoAppConfig.class);
AnnotationConfigApplicationContext๋ AutoAppConfig์ ์ธ์๋ฅผ ๋ฐ์ ์คํ๋ง ์ค์ ํด๋์ค๋ก ์ธ์ํ๋ค. AutoAppConfig์ @Configuration์ ์ ์ด๋์์ผ๋ ์ธ์์ด ๋๋ ๊ฒ์ด๋ค. AutoAppConfig์๋ ์๊น @Componentscan์ ๋ํ ์ ๋ณด๋ค์ ์ ์ด๋์๋ค. ๊ทธ๋ผ ๊ทธ๊ฑธ ๊ธฐ๋ฐ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์ค์บํด ๋น์ผ๋ก ๋ฑ๋กํ๊ณ ์์กด์ฑ์ ์ฃผ์ ํ๋ค. ๋ชจ๋ ์ค๋น๊ฐ ์๋ฃ๋๋ฉดAnnotationConfigApplicationContext๋ ์์ ํ ์ด๊ธฐํ๋๋ฉฐ ๊ธฐ๋ฅ์ ์ํํ๊ฒ ๋๋ค.
••• ์ด์ด์ ๋ค๋ฅธ ์ฝ๋ ๋ถ๋ถ •••
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberService.class);
}
์คํ๋ง ์ปจํ ์ด๋์์ MemberService ํ์ ์ ๋น์ ์กฐํํ๋ค. ์กฐํ๋ ๋น์ด MemberServiceํ์ ์ธ์ง ๊ฒ์ฆํ์ฌ ์ค์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๋ค.
assertThat(A).isInstanceOf(B);
: isInstanceOf() ๋ ํด๋น ํ์ ์ ์ธ์คํด์ค์ธ์ง๋ฅผ ๋น๊ตํ๋ ๋ฉ์๋๋ค.
โ๏ธ MyExcludeComponent
์ปดํฌ๋ํธ ์ค์บ ๋์์์ ์ ์ธํ ์ ๋ ธํ ์ด์
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
@interface
: ์๋ฐ์์ ์ ๊ณตํ๋ ์ด๋ ธํ ์ด์ ์ธ์, ์ฌ์ฉ์๊ฐ ์ปค์คํ ํ ์ ์๋ ์ด๋ ธํ ์ด์ ์ด๋ค. @interface๋ ํด๋์ค๋ ๋ณ์๋ฅผ ํน์ ๊ฐ์ผ๋ก ์ง์ ํ์ฌ ๊ด๋ฆฌํ ์ ์๋ค.
@Target
: ์ฌ์ฉ์๊ฐ ๋ง๋ annotation์ด ๋ถ์ฐฉ๋ ์ ์๋ ํ์ ์ ์ง์ ํ๋ค.
@Target({ElementType.TYPE})์ ํด๋์ค, ์ธํฐํ์ด์, Enum ๋๋ Record์ ๋ถ์ผ ์ ์๋ค๋ ์๋ฏธ์ด๋ค.
@Retention
: ํด๋น ์ด๋ ธํ ์ด์ ์ ์ธ์ ๊น์ง ์ ์งํ ๊ฑด์ง ์ง์ ํ๋ค.
@Retention(RetentionPolicy.RUNTIME)์ Java๋ก ์์ฑํ ์ฝ๋๊ฐ ๋์๊ฐ๋ ๋์ ์ ์งํ๋ค๋ ์๋ฏธ์ด๋ค.
@Documented
: ์ด๋ ธํ ์ด์ ์ ๋ํ ์ ๋ณด๊ฐ javadoc์ผ๋ก ์์ฑํ ๋ฌธ์์ ํฌํจ๋๋๋ก ํ๋ ์ด๋ ธํ ์ด์ ์ด๋ค.
Q. Docummented๋ฅผ ์จ์ ๋ฌธ์์ ํฌํจ๋๋๋ก ํ๋ ์ด์ ๊ฐ ๋ฌด์์ธ๊ฐ?
A. ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ๊ฐ๋ฐ๋ ์ฝ๋๋ฅผ ๋ณด์์ ๋ ์ด๋ค ์ฝ๋์ธ์ง ์ฝ๊ฒ ํ์ ํ ์ ์๋๋ก ํด์ค๋ค. ์ด๋ ธํ ์ด์ ์ ์ ์ผ๋์ง ๋ฑ ์ค๋ช ์ ํฌํจ์ํฌ ์ ์๊ธฐ ๋๋ฌธ์ @Documented๋ฅผ ํจ๊ป ์ ์ด ๋ค๋ฅธ ๊ฐ๋ฐ์์ ์ดํด๋ฅผ ๋๋๋ค. ํนํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ๋ ์์ํฌ ๊ฐ๋ฐํ ๋ ์ ์ฉํ๋ค.
โ๏ธ BeanB
์ปดํฌ๋ํธ ์ค์บ์์ ์ ์ธํ ํด๋์ค
@MyExcludeComponent
public class BeanB {
}
์์ง๊น์ง ์ ์ธ๋ฅผ ํ ์ ์๋ ์ด๋ค ๊ธฐ๋ฅ์ด ์คํ๋ ๊ฒ์ ์๋๋ค. @MyExcludeComponent๋ฅผ ์ ์ด์ฃผ์ด ์๊น ๋ง๋ค์๋ ์ ๋ ธํ ์ด์ ๊ณผ ์ฐ๊ฒฐํ๋ค.
Q. ์ ์ ๋ ธํ ์ด์ ์ ๋ง๋๋๊ฐ?
A. ์ ๋ ธํ ์ด์ ์ ๋ง๋๋ ์ด์ ๋ ์ฌ์ฉ์๊ฐ ์ํ๋๋๋ก ์ค์ ์ ๋ณด๋ฅผ ์ปค์คํ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๊ผญ ์ปดํฌ๋ํธ ์ค์บ์ ์ด๋ค ํด๋์ค๋ฅผ ํฌํจํ๊ณ ์ ์ธ์ํค๊ธฐ ์ํจ์ ์๋๋ค. (์ ์ธ๋ ๋ค๋ฅธ ํด๋์ค์์ ๋ถ์ฌํจ) ์๊น ๋ฐํ์ ์๊ฐ์ ์ง์ ํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๊ฐ๋ฐ์๊ฐ ํ์ํ ์ค์ ์ ๋ณด๋ฅผ ๋ง๋ค์ด ๋ค๋ฅธ ํด๋์ค์ ํธ๋ฆฌํ๊ฒ ๋ถ์ฌํ ์ ์๋ค.
โ๏ธ ComponentFilterAppConfigTest
BeanA beanA = ac.getBean("beanA", BeanA.class);
Assertions.assertThat(beanA).isNotNull();
getBean
: ac(์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ)์์ beanA ์ด๋ฆ์ผ๋ก BeanA๋ผ๋ ํ์ ์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ปํ๋ค.
Assertions.assertThat(A).isNotNull( )
: A๊ฐ Null์ธ์ง ํ์ธํ๋ค.
- Assertions.assertThat().isNotNull() ์ถ์ฒ
assertThrows(
NoSuchBeanDefinitionException.class,
() -> ac.getBean("beanB", BeanB.class));
}
NoSuchBeanDefinitionException
: BeanFactory์ ์๋ฅผ ์ฐพ์ ์ ์๋ ๋น ์ธ์คํด์ค๋ฅผ ์์ฒญํ์ ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ค.
NoSuchBeanDefinitionException.class, () -> ac.getBean("beanB", BeanB.class)์ BeanB๋ฅผ beanB๋ผ๋ ์ด๋ฆ์ผ๋ก ๊ฐ์ง๊ณ ์๋๋ฐ ๊ทธ๊ฒ ์ ์๋ฅผ ์ฐพ์ ์ ์๋ ๋น ์ธ์คํด์ค์ฌ์ผ ํ ์คํธ๊ฐ ์ฑ๊ณตํ๋ ๊ฒ์ด๋ค.
- NoSuchBeanDefinitionException ์ถ์ฒ
••• ์ด์ด์ ๋ค๋ฅธ ์ฝ๋ ๋ถ๋ถ •••
@ComponentScan(
includeFilters = @Filter(classes = MyIncludeComponent.class),
excludeFilters = @Filter(classes = MyExcludeComponent.class)
)
@Filter
: ํํฐ๋ ์ฃผ๋ก ์์ฒญ์ ๋ํ ์ธ์ฆ, ๊ถํ ์ฒดํฌ ๋ฑ์ ์ด๋ค. ๊ตฌ์ฒด์ ์ผ๋ก ๋ค์ด์จ ์์ฒญ์ด DispatcherServlet์ ์ ๋ฌ๋๊ธฐ ์ , ํค๋๋ฅผ ๊ฒ์ฌํด ์ธ์ฆ ํ ํฐ์ด ์๋์ง ์๋์ง, ์ฌ๋ฐ๋ฅธ์ง, ์ณ์ง ์์์ง ๋ฑ์ ๊ฒ์ฌํ๋ค.
excludeFilters
: ์์ฑ์ ์ฌ์ฉํ์ฌ ํน์ ๋์์ ์ค์บ์์ ์ ์ธ์ํจ๋ค.
Q. ๊ทธ๋ผ ๋ค์ ํฌํจ์ํค๊ณ ์ถ์ผ๋ฉด ์ด๋ป๊ฒ ํด์ผํ๋?
A. includeFilters = @Filter(classes = MyExcludeComponent.class)๋ก ๋ฐ๊ฟ์ฃผ๋ฉด ๋๋ค.
@ComponentScan์ ํตํด ์์ฑ์ ์ดํด๋ณธ๋ค. ์์ฑ์ MyExcludeComponent๋ฅผ excludeFiltersํ๋ผ๊ณ ์ ํ์๋ค. ๊ทธ๋ฌ๋ฉด MyExcludeComponent๋ฅผ ์ ์ธ์ํค๋๋ก ๋์ด์์ผ๋ @MyExcludeComponent๊ฐ ๋ถ์ด์์ผ๋ฉด ์ ์ธ์ํค๋๋ก ํ๋ค. ๊ทธ๋ฐ๋ฐ BeanB์๋ @MyExcludeComponent๊ฐ ๋ถ์ด์์ผ๋ ์ ์ธ๊ฐ ๋์๋ค.
๐ท
์ปดํฌ๋ํธ ์ค์บ์ด ํ์ํ ๊ฒฝ์ฐ @ComponentScan์ ์ฐ๊ณ { } ์์ ์ํ๋ ํน์ฑ์ ๋ฃ์ ์ ์์์ ์์๋ดค๋ค.
๊ทธ๋ฆฌ๊ณ ์ปดํฌ๋ํธ ์ค์บ์ ๋ํ ์๊ตฌ๋ฅผ ์ค์ ํ๊ณ ์ถ์ ๊ฒจ์ฐ @interface์ ํด๋์ค๋ฅผ ์ฐ๊ฒฐ์ํฌ ์ ์๋ค.