Spring / @ComponentScan, @Component
by rlaehddnd0422@ComponentScan์ ์ด์ฉํ Bean ๋ฑ๋ก
์ง๊ธ๊น์ง ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋๋ ์๋ฐ ์ฝ๋์ @Bean์ ํตํด์๋ ๋๋ XML์ <bean> ์ ํตํด ์ค์ ์ ๋ณด(AppConfig)์ ์ง์ ๋ฑ๋กํ ๋น๋ค์ ๋์ดํ์๋ค.
์์ ์์๋ ๋ช ๊ฐ ์์์ง๋ง, ๋ฑ๋กํด์ผ ํ ๋น์ด ์์ญ๊ฐ, ์๋ฐฑ๊ฐ๊ฐ ๋๋ฉด ์ผ์ผ์ด ๋ฑ๋กํ๊ธฐ ๊ท์ฐฎ๊ณ , ์ค์ ์ ๋ณด ์์ฒด๊ฐ ์ปค์ ธ ๋๋ฝํ๋ ๋ฌธ์ ๊น์ง ๋ฐ์ํ ์ ์๋ค.
๊ทธ๋์ ์คํ๋ง์ ์ค์ ์ ๋ณด ์์ด ์๋์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ ์ปดํฌ๋ํธ ์ค์บ์ด๋ผ๋ ๊ธฐ๋ฅ์ ์ ๊ณต
+ ์์กด๊ด๊ณ๋ ์๋์ผ๋ก ์ฃผ์ ํ๋ @Autowired๋ผ๋ ๊ธฐ๋ฅ๋ ์ ๊ณต
package hello.core;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan(
excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}
์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด @Configuration์ด ๋ถ์ ์ค์ ์ ๋ณด(AppConfig)๋ ์๋์ผ๋ก ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์, ๊ธฐ์กด์ ์๋ AppConfig์ ์ํฅ์ด ๊ฐ์ง ์๋๋ก excludeFilter๋ฅผ ์ฌ์ฉํด์ ๊ธฐ์กด์ ์ค์ ์ ๋ณด๋ ์ค์บ ๋์์์ ์ ์ธ์์ผฐ๋ค.
(๋ณดํต ์ค์ ์ ๋ณด๋ฅผ ์ปดํฌ๋ํธ ์ค์บ ๋์์์ ์ ์ธํ์ง๋ ์์ง๋ง, ๊ธฐ์กด ์์ ์ฝ๋๋ฅผ ์ต๋ํ ๋จ๊ธฐ๊ณ ์ ์งํ๊ธฐ ์ํด์)
@ComponentScan์ ์ด๋ฆ ๊ทธ๋๋ก @Component ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ํด๋์ค๋ฅผ ์ค์บํด์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
์ด์ ๋ฑ๋กํ ๋น๋ค์ @Component๋ฅผ ๋ถํ ๋น์ ๋ฑ๋กํ๊ณ ํ ์คํธ ํด๋ณด์.
@Component
public class MemoryMemberRepository implements MemberRepository{
@Component
public class RateDiscountPolicy implements DiscountPolicy{
+ ์์กด๊ด๊ณ ์ฃผ์ ํ ๋์๋ @Autowired๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
@Component
public class MemberServiceImp implements MemberService{
private final MemberRepository memberRepository;
@Autowired // ac.getBean(MemberRepository.class)
public MemberServiceImp(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Component
public class OrderServiceImp implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImp(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
์ด ์ AppConfig์์๋ @Bean์ผ๋ก ์ง์ ์ค์ ์ ๋ณด๋ฅผ ์์ฑํ๊ณ , ์์กด๊ด๊ณ๋ ์ง์ ๋ช ์ํ๋ค.
์ด์ ๋ ์ด๋ฐ ์ค์ ์ ๋ณด ์์ฒด๊ฐ ์๊ธฐ ๋๋ฌธ์, ์์กด๊ด๊ณ ์ฃผ์ ๋ ์ด ํด๋์ค ์์์ ํด๊ฒฐํด์ผ ํ๋ค.
@Autowired๋ ์์กด๊ด๊ณ๋ฅผ ์๋์ผ๋ก ์ฃผ์ ํด์ค๋ค.
Testcode
public class AutoAppConfigTest {
@Test
void basicBean()
{
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
MemberService bean = ac.getBean(MemberService.class);
Assertions.assertThat(bean).isInstanceOf(MemberServiceImp.class);
}
}
์ค์ ์ ๋ณด๋ก AutoAppConfig ํด๋์ค๋ฅผ ๋๊ฒจ์ค๋ค.
์คํํด๋ณด๋ฉด ๊ธฐ์กด๊ณผ ๊ฐ์ด ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ก๊ทธ๋ฅผ ์๋ณด๋ฉด ์ปดํฌ๋ํธ ์ค์บ์ด ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค
๋์์๋ฆฌ๋ฅผ ์์๋ณด์.
1. @ComponentScan
์ฐ์ @ComponentScan์ @Component ๊ฐ ๋ถ์ ๋ชจ๋ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
์ด ๋ ๋น์ ๊ธฐ๋ณธ์ด๋ฆ์ ํด๋์ค๋ช ์ ์ฌ์ฉํ๋๋ฐ, ์๊ธ์๊ฐ ์๋ฌธ์๋ก ๋ฐ๋
- ๋น ์ด๋ฆ ๊ธฐ๋ณธ ์ ๋ต : MemberServiceImp -> memberServiceImp
๋ง์ฝ ๋น์ ์ด๋ฆ์ ์ง์ ํ๊ณ ์ถ๋ค๋ฉด @Component("์ง์ ์ด๋ฆ")์ผ๋ก ๋ถ์ฌํ๋ฉด ๋๋ค.
2. @Autowired ์์กด๊ด๊ณ ์ฃผ์
์์ฑ์์ @Autowired๋ฅผ ์ง์ ํ๋ฉด ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์๋์ผ๋ก ๋น์ ์ฐพ์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํด์ค๋ค.
ac.getBean(MemberRepository.class)์ ๋์ผํ๋ค๊ณ ๋ณด๋ฉด ๋จ.
์ด๋ ๊ธฐ๋ณธ ์กฐํ ์ ๋ต์ ํ์ ์ ๋ณด๊ณ ๋น์ ์ฐพ์์ ์ฃผ์ ํ๋๋ฐ ๋ง์ฝ ๊ฐ์ ํ์ ์ด ์ปดํฌ๋ํธ๋ก ์ฌ๋ฌ ๊ฐ ์ง์ ๋์ด ์์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น??
๋ค์์ ๋ค๋ฃจ๋๋ก ํ๊ฒ ๋ค.
@ComponentScan ํ์ ์์น
๋ชจ๋ ์๋ฐ ํด๋์ค๋ฅผ ๋ค ์ปดํฌ๋ํธ ์ค์บํ๋ฉด ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์, ํ์ํ ํจํค์ง์ ์์ ์์น๋ฅผ @ComponentScan์ basePackages ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ํด์ ๋ณ๊ฒฝํ ์ ์๋ค.
@ComponentScan(
basePackages = {"hello.core"} )
basePackages : ์์์์น๋ฅผ ์ง์ ํด์ ํด๋น์์น์ ํ์ ํจํค์ง๋ฅผ ๋ชจ๋ ํ์ํ๋ค.
basePackages = {"hello.core", "hello.service"} ์ด๋ ๊ฒ ์ฌ๋ฌ ์์ ์์น๋ฅผ ์ง์ ํ ์๋ ์๋ค.
๋ง์ฝ ์ง์ ํ์ง ์์ผ๋ฉด @ComponentScan์ด ๋ถ์ ์ค์ ์ ๋ณด ํด๋์ค์ ํจํค์ง๊ฐ ์์ ์์น๊ฐ ๋๋ค.
๊ถ์ฅํ๋ ๋ฐฉ๋ฒ
๊ทธ๋ฅ @ComponentScan์ด ๋ถ์ ์ค์ ์ ๋ณด ํด๋์ค์ ์์น๋ฅผ ํ๋ก์ ํธ ์ต์๋จ์ ๋์.
์ต๊ทผ ์คํ๋ง ๋ถํธ๋ ์ด ๋ฐฉ๋ฒ์ default๋ก ์ ๊ณตํ๋ค๊ณ ํ๋ค.
์๋ฅผ๋ค์ด
kdo6301.core.hello
kdo6301.core.hello.service
kdo6301.core.hello.repository ๊ฐ ์๋ค๊ณ ํ๋ฉด
kdo6301.core.hello์ ์ค์ ์ ๋ณด ํด๋์คํ์ผ์ ๋์๋ ๊ฒ์ด๋ค.
ํด๋์คํ์ผ์ ์ต์๋จ์ ๋๊ณ @ComponentScan๋ง ๋ถํ์ฃผ๊ณ basePackage ์ง์ ์๋ต.
์ด๊ฒ ์ ์ผ ๊น๋ํ๋ค.
์ด๋ ๊ฒ ํ๋ฉด kdo6301.core.hello ๋ฅผ ํฌํจํ ํ์๋ ๋ชจ๋ ์๋์ผ๋ก ์ปดํฌ๋ํธ ์ค์บ์ ๋์์ด ๋๋ค.
โ๏ธ ์ฐธ๊ณ ๋ก ์คํ๋ง ๋ถํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์คํ๋ง ๋ถํธ์ ๋ํ ์์ ์ ๋ณด์ธ @SpringBootApplication ๋ฅผ ์ด ํ๋ก์ ํธ ์์ ๋ฃจํธ ์์น์ ๋๋ ๊ฒ์ด ๊ด๋ก์ด๋ค. (๊ทธ๋ฆฌ๊ณ ์ด ์ค์ ์์ ๋ฐ๋ก @ComponentScan ์ด ๋ค์ด์๋ค!)
@ComponentScan ๊ธฐ๋ณธ ๋์
์ปดํฌ๋ํธ ์ค์บ์ ๊ธฐ๋ณธ์ ์ผ๋ก @Component ๋ฟ๋ง ์๋๋ผ
@Controller, @Service, @Repository, @Configuration๋ ์ถ๊ฐ๋ก ๋์์ ํฌํจํ๋ค.
1. @Controller : Spring MVC Controller์์ ์ฌ์ฉ
2. @Service : Spring Buisness ๋ก์ง์์ ์ฌ์ฉ
3. @Repository : Spring ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์์ ์ฌ์ฉ
4. @Configuration : Spring ์ค์ ์ ๋ณด์์ ์ฌ์ฉ (AppConfig)
@Repository๋ ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ๊ณ ์์ด ๋น ๋ฑ๋ก ๋ฟ๋ง ์๋๋ผ ์คํ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์ผ๋ก ์ธ์ํ๊ณ , ๋ฐ์ดํฐ ๊ณ์ธต์ ์์ธ๋ฅผ ์คํ๋ง ์์ธ๋ก ๋ณํํด์ค๋ค.
@Controller๋ ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ๊ณ ์์ด ๋น ๋ฑ๋ก ๋ฟ๋ง ์๋๋ผ ์คํ๋ง MVC Controller๋ก ์ธ์ํ๊ฒ ํด์ค๋ค.
@Service๋ ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ๊ณ ์์ด ๋น ๋ฑ๋ก์ ํด์ฃผ์ง๋ง ๊ทธ ์ธ์ ๋ณ๋ค๋ฅธ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์๋๋ค.
๋จ์ํ๊ฒ ํต์ฌ ๋น์ฆ๋์ค ๊ณ์ธต์ ๊ฐ๋ฐ์๊ฐ ์ธ์ํ๊ธฐ ์ฝ๊ฒ ํด์ฃผ๊ธฐ ์ํด ์ฌ์ฉ
@Configuration์ ๋น๋ฑ๋ก ๋ฟ๋ง ์๋๋ผ ์์ ๋ณด์๋ฏ์ด ์คํ๋ง ์ค์ ์ ๋ณด๋ก ์ธ์ํ๊ณ , ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ ์ ์งํ๋๋ก ์ถ๊ฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
โ๏ธ ์ฐธ๊ณ : useDefaultFilters ์ต์ ์ ๊ธฐ๋ณธ์ผ๋ก ์ผ์ ธ์๋๋ฐ, ์ด ์ต์ ์ ๋๋ฉด ๊ธฐ๋ณธ ์ค์บ ๋์๋ค์ด ์ ์ธ๋๋ค. ๊ทธ๋ฅ ์ด๋ฐ ์ต์ ์ด ์๊ตฌ๋ ์ ๋ ์๊ณ ๋์ด๊ฐ์.
@ComponentScan Filter
@ComponentScan์๋ ํํฐ๋ฅผ ์ฌ์ฉํด์ ์ปดํฌ๋ํธ ์ค์บ ๋์์ ์ถ๊ฐ๋ก ์ง์ ํ๊ฑฐ๋ ์ ์ธํ ์ ์๋ค.
@MyIncludeComponent
public class BeanA {
}
@MyExcludeComponent
public class BeanB {
}
package hello.core.scan;
import hello.core.scan.filter.BeanA;
import hello.core.scan.filter.BeanB;
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;
public class ComponentFilterTest {
@Configuration
@ComponentScan(
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
)
static class ComponentFilterAppConfig{
}
@Test
void filterScan()
{
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean(BeanA.class);
System.out.println("beanA = " + beanA);
assertThat(beanA).isNotNull();
Assertions.assertThrows(
NoSuchBeanDefinitionException.class,
() -> ac.getBean(BeanB.class)
);
}
}
- includeFilters์ MyIncludeComponent ์ ๋ ธํ ์ด์ ์ ์ถ๊ฐํด์ BeanA๊ฐ ์คํ๋ง ๋น์ ๋ฑ๋ก๋๋ค.
- excludeFilters์ MyExcludeComponent ์ ๋ ธํ ์ด์ ์ ์ถ๊ฐํด์ BeanB๋ ์คํ๋ง ๋น์ ๋ฑ๋ก๋์ง ์๋๋ค.
์ฐธ๊ณ : @Component ๋ฉด ์ถฉ๋ถํ๊ธฐ ๋๋ฌธ์, includeFilters ๋ฅผ ์ฌ์ฉํ ์ผ์ ๊ฑฐ์ ์๋ค. excludeFilters ๋ ์ฌ๋ฌ๊ฐ์ง ์ด์ ๋ก ๊ฐํน ์ฌ์ฉํ ๋๊ฐ ์์ง๋ง ๋ง์ง๋ ์๋ค.
ํนํ ์ต๊ทผ ์คํ๋ง ๋ถํธ๋ ์ปดํฌ๋ํธ ์ค์บ์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋๋ฐ, ๊ฐ์ธ์ ์ผ๋ก๋ ์ต์ ์ ๋ณ๊ฒฝํ๋ฉด์ ์ฌ์ฉํ๊ธฐ ๋ณด๋ค๋ ์คํ๋ง์ ๊ธฐ๋ณธ ์ค์ ์ ์ต๋ํ ๋ง์ถ์ด ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๊ณ , ์ ํธํ๋ ํธ์ด๋ค.
์ค๋ณต๋ฑ๋ก๊ณผ ์ถฉ๋
์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก
@Component("myService")
public class MemberServiceImp implements MemberService{
private final MemberRepository memberRepository;
@Component("myService")
public class OrderServiceImp implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
๋ค์๊ณผ ๊ฐ์ด ์๋์ผ๋ก @Component๋ฅผ ์ง์ ํด์ ์ด๋ฆ์ด ๊ฐ์ ๋น์ ๋ฑ๋กํ์ฌ ํ ์คํธ๋ฅผ ๋๋ ค๋ณด๋ฉด
๋ค์๊ณผ ๊ฐ์ด ์ถฉ๋์ด ๋ฐ์ํ์ฌ ์์ธ๊ฐ ๋ฐ์ํ๋ค.
์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก
@Configuration
@ComponentScan(
excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
@Bean(name="memoryMemberRepository")
public MemberRepository memberRepository()
{
return new MemoryMemberRepository();
}
}
์๋์ผ๋ก ๋ฑ๋ก๋ ๋น์ด ์ฐ์ ๊ถ์ ๊ฐ์ง๋ค! ์๋ ๋น์ด ์๋ ๋น์ ์ค๋ฒ๋ผ์ด๋ฉ ํด๋ฒ๋ฆผ.
17:43:11.644 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'memoryMemberRepository' with a different definition
๋ฌผ๋ก ๊ฐ๋ฐ์๊ฐ ์๋์ ์ผ๋ก ์ด๋ฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ํ๋ค๋ฉด, ์๋ ๋ณด๋ค๋ ์๋์ด ์ฐ์ ๊ถ์ ๊ฐ์ง๋ ๊ฒ์ด ์ข๋ค. ํ์ง๋ง ํ์ค์ ๊ฐ๋ฐ์๊ฐ ์๋์ ์ผ๋ก ์ค์ ํด์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋ง๋ค์ด์ง๊ธฐ ๋ณด๋ค๋ ์ฌ๋ฌ ์ค์ ๋ค์ด ๊ผฌ์ฌ์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋ง๋ค์ด์ง๋ ๊ฒฝ์ฐ๊ฐ ๋๋ถ๋ถ์ด๋ผ๊ณ ํ๋ค.
๊ทธ๋ฌ๋ฉด ์ ๋ง ์ก๊ธฐ ์ด๋ ค์ด ๋ฒ๊ทธ๊ฐ ๋ง๋ค์ด์ง๋ค. ํญ์ ์ก๊ธฐ ์ด๋ ค์ด ๋ฒ๊ทธ๋ ์ ๋งคํ ๋ฒ๊ทธ๋ค.
๊ทธ๋์ ์ต๊ทผ ์คํ๋ง ๋ถํธ์์๋ ์๋ ๋น ๋ฑ๋ก๊ณผ ์๋ ๋น ๋ฑ๋ก์ด ์ถฉ๋๋๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ก ๊ธฐ๋ณธ ๊ฐ์ ๋ฐ๊พธ์๋ค.
์คํ๋ง ๋ถํธ์ธ CoreApplication ์ ์คํํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๋ฅผ ๋ณผ ์ ์๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring / ์์กด๊ด๊ณ ์ฃผ์ - @Autowired ์ต์ ์ฒ๋ฆฌ, ์์ฑ์ ์ฃผ์ ์ฌ์ฉ ๊ถ์ฅ (0) | 2023.02.06 |
---|---|
Spring / ์์กด๊ด๊ณ ์ฃผ์ - ์์ฑ์, ์์ ์, ํ๋, ๋ฉ์๋ (0) | 2023.02.03 |
Spring / Single-ton Pattern, Single-ton Container (0) | 2023.01.31 |
Spring / Spring Container, Bean (0) | 2023.01.30 |
Spring / IoC, DI, Container (0) | 2023.01.30 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422