๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Spring/[์ธํ”„๋Ÿฐ] ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ

์ปดํฌ๋„ŒํŠธ ์Šค์บ”

ํ•ด๋‹น ํฌ์ŠคํŒ…์€ ๊น€์˜ํ•œ๋‹˜์˜ ์ธํ”„๋Ÿฐ ๊ฐ•์˜(์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ธฐ๋ณธํŽธ)๋ฅผ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

@ComponentScan

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•  ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด @Bean(๋˜๋Š” XML์˜ <bean>)์„ ํ†ตํ•ด์„œ ์„ค์ • ์ •๋ณด๋ฅผ ์ง์ ‘ ๋“ฑ๋กํ•  ์Šคํ”„๋ง ๋นˆ์„ ๋‚˜์—ดํ•ด์•ผํ–ˆ๋‹ค.

// ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” Configuration
@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
	
    ...
    
}

 

์Šคํ”„๋ง์€ ์„ค์ • ์ •๋ณด๊ฐ€ ์—†์–ด๋„ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด๋ผ๋Š” ๊ธฐ๋Šฅ๊ณผ ์˜์กด๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด @ComponentScan ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋นˆ ๋“ฑ๋ก์„ ์ง์ ‘ํ•˜์ง€ ์•Š์•„๋„, @Component ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋“ค์„ ์ฐพ์•„ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ค€๋‹ค.

์ด๋•Œ ๋นˆ๋“ค ๊ฐ„์˜ ์˜์กด ๊ด€๊ณ„๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ƒ์„ฑ์ž ๋˜๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•œ ํ•„๋“œ์— @Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๊ฒŒ๋˜๋ฉด ์ž๋™์œผ๋กœ ์ฃผ์ž…์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

// AutoAppConfig.java
@Configuration
@ComponentScan
public class AutoAppConfig {
}

// MemberServiceImpl.java
@Component
public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
	
    ...

}

@ComponentScan

  • @ComponentScan์€ @Component๊ฐ€ ๋ถ™์€ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.
  • ์ด๋•Œ ์Šคํ”„๋ง ๋นˆ์˜ ๊ธฐ๋ณธ ์ด๋ฆ„์€ ํด๋ž˜์Šค๋ช…์„ ์‚ฌ์šฉํ•˜๋˜ ๋งจ ์•ž๊ธ€์ž๋งŒ ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์ง์ ‘ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด @Component("customBeanName")์ฒ˜๋Ÿผ ์ด๋ฆ„์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

@Autowired

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

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

ํƒ์ƒ‰ ์œ„์น˜

ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@ComponentScan(
        basePackages = {"hello.core", "hello.service"},
        basePackageClasses = CoreApplication.class
)
  • basePackages : ํƒ์ƒ‰ํ•  ํŒจํ‚ค์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์ด ํŒจํ‚ค์ง€๋ฅผ ํฌํ•จํ•ด์„œ ํ•˜์œ„ ํŒจํ‚ค์ง€๋ฅผ ๋ชจ๋‘ ํƒ์ƒ‰ํ•œ๋‹ค.
  • basePackageClasses : ์ง€์ •ํ•œ ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๋ฅผ ํƒ์ƒ‰ ์‹œ์ž‘ ์œ„์น˜๋กœ ์ง€์ •ํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด @ComponentScan์ด ๋ถ™์€ ์„ค์ • ์ •๋ณด ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๊ฐ€ ์‹œ์ž‘ ์œ„์น˜๊ฐ€ ๋œ๋‹ค.

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

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ๋Œ€ํ‘œ ์‹œ์ž‘ ์ •๋ณด์ธ @SpringBootApplication์„ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๋ฃจํŠธ ์œ„์น˜์— ๋‘๋Š” ๊ฒƒ์ด ๊ด€๋ก€์ด๊ณ , ์ด @SpringBootApplication ์„ค์ • ์•ˆ์— @ComponentScan์ด ๋“ค์–ด์žˆ๋‹ค.

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

  • @Component : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์‚ฌ์šฉ
  • @Controller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‚ฌ์šฉ
  • @Service : ์Šคํ”„๋ง ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์‚ฌ์šฉ
  • @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ (ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์œผ๋กœ ์ธ์‹ํ•˜๊ณ , ๋ฐ์ดํ„ฐ ๊ณ„์ธต์˜ ์˜ˆ์™ธ๋ฅผ ์Šคํ”„๋ง ์˜ˆ์™ธ๋กœ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค)
  • @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์—์„œ ์‚ฌ์šฉ

ํ•„ํ„ฐ

ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์„ ์ถ”๊ฐ€๋กœ ์ง€์ •ํ•˜๊ฑฐ๋‚˜ ์ œ์™ธํ•  ์ˆ˜ ์žˆ๋‹ค.

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

FilterType ์˜ต์…˜

  • ANNOTATION : ๊ธฐ๋ณธ๊ฐ’, ์–ด๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค.
  • ASSIGNABLE_TYPE : ์ง€์ •ํ•œ ํƒ€์ž…๊ณผ ์ž์‹ ํƒ€์ž…์„ ์ธ์‹ํ•ด์„œ ๋™์ž‘ํ•œ๋‹ค.
  • ASPECTJ : AspectJ ํŒจํ„ด ์‚ฌ์šฉ
  • REGEX : ์ •๊ทœ ํ‘œํ˜„์‹
  • CUSTOM : TypeFilter ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ฒ˜๋ฆฌ

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


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

  • ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ž๋™ ๋นˆ ๋“ฑ๋ก
    • ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์ด ๋“ฑ๋ก๋˜๋Š”๋ฐ, ๊ทธ ์ด๋ฆ„์ด ๊ฐ™์€ ๊ฒฝ์šฐ ์Šคํ”„๋ง์€ ConflictingBeanDefinitionException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
  • ์ž๋™ ๋นˆ ๋“ฑ๋ก vs ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก
    • ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก์ด ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง„๋‹ค. 
    • ํ•˜์ง€๋งŒ ์ตœ๊ทผ ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ๋Š” ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก๊ณผ ์ž๋™ ๋นˆ ๋“ฑ๋ก์ด ์ถฉ๋Œ๋‚˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ๊ธฐ๋ณธ ๊ฐ’์„ ๋ฐ”๊พธ์—ˆ๋‹ค.