[Spring] 6.์ปดํฌ๋„ŒํŠธ ์Šค์บ”

 

1. ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž… ์‹œ์ž‘ํ•˜๊ธฐ

์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž… ์‹œ์ž‘ํ•˜๊ธฐ

- ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๊ฐ€ ์—†์–ด๋„ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด๋ผ๋Š” ๊ธฐ๋Šฅ ์ œ๊ณต

- ์˜์กด๊ด€๊ณ„๋„ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•˜๋Š” @Autowired ๊ธฐ๋Šฅ ์ œ๊ณต

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

AutoAppConfig

@Configuration
@ComponentScan (excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
        Configuration.class))
public class AutoAppConfig {
}

- @ComponentScan : @Component ๋ถ™์€ ํด๋ž˜์Šค ์ž๋™์œผ๋กœ ์ฐพ์•„์„œ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก

- exludeFilters -> ๋บ„๊ฑฐ ์ง€์ • (Configuration ๊ธฐ์กด ์˜ˆ์ œ ๋•Œ๋ฌธ์—)

 

@Component์ถ”๊ฐ€

- MMRepo, DiscountPolicy, ServiceImpl(Member, Order)

 

@Autowired์ถ”๊ฐ€ (์ž๋™ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…)

- ServiceImpl (Member, Order)

 

ํ…Œ์ŠคํŠธ

public class AutoAppConfigTest {
  @Test
  void basicScan() {
    ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
    MemberService memberService = ac.getBean(MemberService.class);
    assertThat(memberService).isInstanceOf(MemberService.class);
  }
}

1) ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋™์ž‘๋ฐฉ๋ฒ•

- @ComponentScan์€ @Component๊ฐ€ ๋ถ™์€ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก

- ์ด๋•Œ ์Šคํ”„๋ง ๋นˆ์˜ ๊ธฐ๋ณธ ์ด๋ฆ„์€ ํด๋ž˜์Šค ๋ช…์œผ๋กœ ๋“ฑ๋กํ•˜๋˜ ๋งจ ์•ž๊ธ€์ž ์†Œ๋ฌธ์ž๋กœ ์‚ฌ์šฉ

   ๋นˆ ์ด๋ฆ„ ๊ธฐ๋ณธ ์ „๋žต: MemberServiceImpl ํด๋ž˜์Šค memberServiceImpl

   ๋นˆ ์ด๋ฆ„ ์ง์ ‘ ์ง€์ •: ๋งŒ์•ฝ ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„์„ ์ง์ ‘ ์ง€์ •ํ•˜๊ณ  ์‹ถ์œผ๋ฉด @Component("memberService2") ์ด๋Ÿฐ์‹์œผ๋กœ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•˜๋ฉด ๋œ๋‹ค.

 

2) @Autowired ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…

- ์ƒ์„ฑ์ž์— @Autowired ์ง€์ •ํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž๋™์œผ๋กœ ํ•ด๋‹น ์Šคํ”„๋ง ๋นˆ ์ฐพ์•„์„œ ์ฃผ์ž…

- ๊ธฐ๋ณธ ์ „๋žต : ํƒ€์ž…์ด ๊ฐ™์€ ๋นˆ ์ฐพ์•„์„œ ์ฃผ์ž…

- getBean(MemberRepository.class) ์™€ ๋™์ผํ•˜๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋จ

 

- ์ƒ์„ฑ์ž ๋งŽ์•„๋„ ๋‹ค ์ฐพ์•„์„œ ์ฃผ์ž…ํ•ด์คŒ


2. ํƒ์ƒ‰ ์œ„์น˜์™€ ๊ธฐ๋ณธ ์Šค์บ” ๋Œ€์ƒ

ํƒ์ƒ‰ํ•  ํŒจํ‚ค์ง€์˜ ์‹œ์ž‘ ์œ„์น˜ ์ง€์ •

- ๊ผญ ํ•„์š”ํ•œ ์œ„์น˜๋ถ€ํ„ฐ ํƒ์ƒ‰ ์‹œ์ž‘ํ•˜๋„๋ก ์„ค์ • ๊ฐ€๋Šฅ

@Configuration
@ComponentScan(
          basePackages = "hello.core",
}

- basePackages : ํƒ์ƒ‰ํ•  ํŒจํ‚ค์ง€์˜ ์‹œ์ž‘ ์œ„์น˜ ์ง€์ • / ์ด ํŒจํ‚ค์ง€๋ฅผ ํฌํ•จํ•ด์„œ ํ•˜์œ„ ํŒจํ‚ค์ง€๋ฅผ ๋ชจ๋‘ ํƒ์ƒ‰

- ์—ฌ๋Ÿฌ ์œ„์น˜๋„ ์„ค์ • ๊ฐ€๋Šฅ (basePackages = {"hello.core", "hello.service"})

- basePackageClasses : ์ง€์ •ํ•œ ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๋ฅผ ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„๋กœ ์ง€์ •

 

๊ถŒ์žฅ๋ฒ• -> ํŒจํ‚ค์ง€ ์œ„์น˜ ์ง€์ •X,์„ค์ • ์ •๋ณด ํด๋ž˜์Šค ์œ„์น˜๋ฅผ ํ”„๋กœ์ ํŠธ ์ตœ์ƒ๋‹จ์— ๋‘๊ธฐ


* ์ฐธ๊ณ ) ์Šคํ”„๋ง๋ถ€ํŠธ :
@SpringBootApplication (์Šคํ”„๋ง๋ถ€ํŠธ ๋Œ€ํ‘œ ์‹œ์ž‘ ์ •๋ณด)๋ฅผ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๋ฃจํŠธ ์œ„์น˜์— ๋‘๋Š” ๊ฒƒ์ด ๊ด€๋ก€

-> ์ด ์„ค์ • ์•ˆ์— @CompentScan์ด ๋“ค์–ด์žˆ์Œ

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๊ธฐ๋ณธ ๋Œ€์ƒ 

- @Component : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์‚ฌ์šฉ

- @Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์— ์‚ฌ์šฉ

- @Service : ์Šคํ”„๋ง ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์‚ฌ์šฉ

- @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ

- @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์—์„œ ์‚ฌ์šฉ

 

 * ์ฐธ๊ณ ) ์Šคํ”„๋ง์—๋Š” ์ƒ์†๊ด€๊ณ„ ์—†์Œ

 

๋ถ€๊ฐ€ ๊ธฐ๋Šฅ

- @Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ธ์‹

- @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์œผ๋กœ ์ธ์‹ / ๋ฐ์ดํ„ฐ ๊ณ„์ธต ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜

- @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด๋กœ ์ธ์‹ / ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค ์œ ์ง€ํ•˜๋„๋ก ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ

- @Service : ํŠน๋ณ„ ์ฒ˜๋ฆฌ ์—†์Œ / ๊ฐœ๋ฐœ์ž๋“ค์ด ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ธ์‹ ์‰ฝ๊ฒŒ

 

* ์ฐธ๊ณ ) useDefaultFilters : ์˜ต์…˜์€ ๊ธฐ๋ณธ์œผ๋กœ ์ผœ์ ธ์žˆ๋Š”๋ฐ, ์ด ์˜ต์…˜์„ ๋„๋ฉด ๊ธฐ๋ณธ ์Šค์บ” ๋Œ€์ƒ๋“ค์ด ์ œ์™ธ 


3. ํ•„ํ„ฐ

์ข…๋ฅ˜

- includeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์„ ์ถ”๊ฐ€๋กœ ์ง€์ •

- excludeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์ œ์™ธํ•  ๋Œ€์ƒ์„ ์ง€์ •

 

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์— ์ถ”๊ฐ€ํ•  annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์— ์ œ์™ธํ•  annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์— ์ถ”๊ฐ€ํ•  class

@MyIncludeComponent
public class BeanA {
  }

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์— ์ œ์™ธํ•  class

@MyExcludeComponent
public class BeanB {
  }

์„ค์ • ์ •๋ณด์™€ ์ „์ฒด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

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 {
  }
  
}

 

FilterType ์˜ต์…˜ (5๊ฐ€์ง€)

- ANNOTATION: ๊ธฐ๋ณธ๊ฐ’, ์• ๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค. (์ƒ๋žต๊ฐ€๋Šฅ)

                             ex) org.example.SomeAnnotation

- ASSIGNABLE_TYPE: ์ง€์ •ํ•œ ํƒ€์ž…๊ณผ ์ž์‹ ํƒ€์ž…์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค.

                                       ex) org.example.SomeClass

- ASPECTJ: AspectJ ํŒจํ„ด ์‚ฌ์šฉ

                     ex) org.example..*Service+

- REGEX: ์ •๊ทœ ํ‘œํ˜„์‹

                 ex) org\.example\.Default.*

- CUSTOM: TypeFilter ์ด๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ฒ˜๋ฆฌ

                     ex) org.example.MyTypeFilter

 

ex) BeanA๋ฅผ ๋นผ๊ณ ์‹ถ์„๋•Œ

@ComponentScan(
    includeFilters = {
      @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
    },
    excludeFilters = {
      @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class),
      @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BeanA.class)
    }
)

์ฐธ๊ณ ) @Component ๋ฉด ์ถฉ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, includeFilters ๋ฅผ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค. excludeFilters ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ด์œ ๋กœ ๊ฐ„ํ˜น ์‚ฌ์šฉํ•  ๋•Œ๊ฐ€ ์žˆ์ง€๋งŒ ๋งŽ์ง€๋Š” ์•Š๋‹ค.

> ํŠนํžˆ ์ตœ๊ทผ ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š”๋ฐ, ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์˜ต์…˜์„ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ์Šคํ”„๋ง์˜ ๊ธฐ๋ณธ ์„ค์ •์— ์ตœ๋Œ€ํ•œ ๋งž์ถ”์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๊ณ , ์„ ํ˜ธํ•˜๋Š” ํŽธ์ด๋‹ค.


4. ์ค‘๋ณต๋“ฑ๋ก๊ณผ ์ถฉ๋Œ

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ๊ฐ™์€ ๋นˆ ์ด๋ฆ„์„ ๋“ฑ๋กํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

1) ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

2) ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

 

1) ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

-> ๋ฉค๋ฒ„์„œ๋น„์Šค์™€ ์˜ค๋”์„œ๋น„์Šค ๋‘˜๋‹ค @Component("sevice") ์ค‘๋ณต

-> ConflictingBeanDefinitionException ์˜ˆ์™ธ ๋ฐœ์ƒ

 

2) ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก

->

  @Configuration
  @ComponentScan(
          excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
  )
  public class AutoAppConfig {
      @Bean(name = "memoryMemberRepository")
      public MemberRepository memberRepository() {
          return new MemoryMemberRepository();
      }
  }

์ด ๊ฒฝ์šฐ ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก์ด ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง„๋‹ค. (์ˆ˜๋™ ๋นˆ์ด ์ž๋™ ๋นˆ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด๋ฒ„๋ฆฐ๋‹ค.)

* ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก์‹œ ๋‚จ๋Š” ๋กœ๊ทธ

Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing

* ์ŠคํŠธ๋ง๋ถ€ํŠธ์—์„œ ์ˆ˜๋™ ๋นˆ vs ์ž๋™ ๋นˆ ์ถฉ๋Œ๋‚˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ๋ณ€๊ฒฝ

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

์Šคํ”„๋ง ๋ถ€ํŠธ์ธ CoreApplication ์„ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 
  • ๋„ค์ด๋ฒ„ ๋ธ”๋Ÿฌ๊ทธ ๊ณต์œ ํ•˜๊ธฐ
  • ๋„ค์ด๋ฒ„ ๋ฐด๋“œ์— ๊ณต์œ ํ•˜๊ธฐ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ ํ•˜๊ธฐ
  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ ๊ณต์œ ํ•˜๊ธฐ