๐ŸƒSpring ์ปดํฌ๋„ŒํŠธ ์Šค์บ”

ํ•ต์‹ฌ์›๋ฆฌ ์‹œ๋ฆฌ์ฆˆ

6 minute read

์•ž์„  ๊ธ€ ๋งˆ์ง€๋ง‰์— ๋งํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ์ด๋ฒˆ์—” ์กฐ๊ธˆ ๋” ์‹ค์ „์ ์ด๊ณ  ์Šคํ”„๋ง์„ ํŽธํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณผ ๊ฒƒ์ด๋‹ค.

  • ์Šคํ”„๋ง์€ ์„ค์ • ์ •๋ณด๊ฐ€ ์—†์–ด๋„ ์ž๋™์œผ๋กœ Bean์„ ๋“ฑ๋กํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”(Component Scan)์ด๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ๋˜ํ•œ ์˜์กด๊ด€๊ณ„๋„ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•˜๋Š” @Autowired ๋ผ๋Š” ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•œ๋‹ค.

์—ด์‹ฌํžˆ AppConfig๋ฅผ ๋งŒ๋“ค๊ณ  @Bean์„ ๋ถ™์—ฌ์„œ ์ƒ์„ฑํ•œ ๋’ค์— getBean()์„ ํ˜ธ์ถœํ•ด์„œ ์–ป์–ด์˜ค๋Š” ์šฐ์•„ํ•˜์ง€ ๋ชปํ•œ(?) ๋ฐฉ์‹์„ ๋ฒ—์–ด๋‚˜, ์Šคํ”„๋ง์ด ์ž๋™์œผ๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ œ๋ถ€ํ„ฐ ๊ตฌ์ฒด์ ์œผ๋กœ ์•Œ์•„๋ณด์ž.

@Configuration  
@ComponentScan()  
public class AutoAppConfig {  
      
}  

ํด๋ž˜์Šค ์•ˆ์˜ ๋‚ด์šฉ์ด ๋ชจ๋‘ ์‚ฌ๋ผ์ ธ๋ฒ„๋ ธ๋‹ค. ๋Œ€์‹  ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์ด๋ผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด ํ•˜๋‚˜ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋ฟ์ด๋‹ค. ์ด์ œ ์ด ๋…€์„์€ @Component๋ผ๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ๋ชฝ๋•… ์ฐพ์•„์„œ(๋‚˜์ค‘์— ๋‚˜๋ฆ„ ๊ทœ์น™์ด ์žˆ๊ธดํ•˜์ง€๋งŒ), Bean์œผ๋กœ ๋“ฑ๋ก์‹œํ‚จ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด.

@Component  
public class MemoryMemberRepository implements MemberRepository {}  
  
@Component("RatePolicyBean")  
public class RateDiscountPolicy implements DiscountPolicy {}  

์ด์ „ ์˜ˆ์ œ๋“ค์—์„œ ์ต์ˆ™ํ•œ ์ด ๋…€์„๋“ค์ด ์• ๋…ธํ…Œ์ด์…˜ ํ•˜๋‚˜์— Bean์œผ๋กœ ๋“ฑ๋ก์ด ๋˜์—ˆ๋‹ค. ๋‘๋ฒˆ์งธ ์• ๋…ธํ…Œ์ด์…˜์ฒ˜๋Ÿผ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด Bean์˜ ์ด๋ฆ„๋„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ์—” ์ด๋ ‡๊ฒŒ ๋“ฑ๋กํ•œ Bean์„ ์ฃผ์ž…๋ฐ›๋Š” ๋ฐฉ์‹๋„ ์‚ดํŽด๋ณด์ž.

@Component  
public class MemberServiceImpl implements MemberService {  
	private final MemberRepository memberRepository;  
  
  @Autowired  
  public MemberServiceImpl(MemberRepository memberRepository) {  
    this.memberRepository = memberRepository;  
  }  
}  

์ด๋ ‡๊ฒŒ ์ž‘์„ฑ์„ ํ•˜๋ฉด MemberServiceImpl ์—ญ์‹œ Bean์ด ๋ ๋ฟ๋”๋Ÿฌ ์ƒ์„ฑ์ž ์œ„์— @Autowired ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ์ž๋™์œผ๋กœ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…์ด ๋œ๋‹ค. ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ํ…Œ์ด๋ธ”์„ ๋’ค์ ธ์„œ ๋งž๋Š” ํƒ€์ž…์˜ Bean ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ด์ „ ๋ฐฉ์‹๋“ค์— ๋น„ํ•ด ์•„์ฃผ์•„์ฃผ ํŽธ๋ฆฌํ•˜๋‹ค. ์ƒ์„ฑ์ž ์™ธ์—๋„ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ ์ถ”ํ›„์— ์•Œ์•„๋ณผ ๊ฒƒ์ด๋ฉฐ ์ƒ์„ฑ์ž ์ฃผ์ž…์ด ๊ฐ€์žฅ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

88 ํŽ˜์ด์ง€ ๊ทธ๋ฆผ ์ฒจ๋ถ€
(๊ทธ๋ฆฌ๊ณ  ๋ญ”๊ฐ€ ๊ฐ•์กฐ๋‚˜ ๋ฐ‘์ค„ ์ด๋Ÿฐ๊ฑฐ ์ž˜ ์•ˆ์“ฐ๊ณ  ์žˆ๋Š”๋“ฏ. ๋‹ค์‹œ ๊ฒ€ํ† )

@ComponentScan(  
	basePackages = {"hello.core", "hello.service"}  
}  

์•„๊นŒ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค๋ผ๋Š” ๋ง์„ ํ–ˆ์—ˆ๋Š”๋ฐ, ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ์œ„์—์„œ ์ง€์ •ํ•œ ๋””๋ ‰ํ† ๋ฆฌ์˜ ํ•˜์œ„์—์„œ ๋ชจ๋“  @Component๋ฅผ ์ฐพ๋„๋ก ๋˜์–ด์žˆ๋‹ค. ์ฒ˜์Œ์ฒ˜๋Ÿผ basePackages๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด @ComponentScan์„ ๋ถ™์ธ ํด๋ž˜์Šค์˜ Package๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋ฉฐ ๋ณดํ†ต ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. (๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ค์ •์ •๋ณด ํด๋ž˜์Šค๋ฅผ ํ”„๋กœ์ ํŠธ์˜ ์ตœ์ƒ๋‹จ์— ๋‘์–ด์•ผํ•  ๊ฒƒ์ด๋‹ค)

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋Œ€์ƒ

  • @Component : ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์—์„œ ์‚ฌ์šฉ
  • @Controlller : ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‚ฌ์šฉ
  • @Service : ์Šคํ”„๋ง ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์‚ฌ์šฉ
  • @Repository : ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉ
  • @Configuration : ์Šคํ”„๋ง ์„ค์ • ์ •๋ณด์—์„œ ์‚ฌ์šฉ

์œ„ ๋‹ค์„ฏ๊ฐ€์ง€ ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๋…€์„(ํด๋ž˜์Šค)๋“ค์€ Bean์ด ๋œ๋‹ค๋Š” ์ด์•ผ๊ธฐ์ด๋‹ค.

@Component  
public @interface Controller {  
  
}  

IntelliJ ๋“ฑ์„ ํ†ตํ•ด @Controller ์• ๋…ธํ…Œ์ด์…˜์„ ๋”ฐ๋ผ๊ฐ€๋ณด๋ฉด ์• ๋…ธํ…Œ์ด์…˜ ์ •์˜ ์œ„์— @Component๊ฐ€ ๋ถ™์–ด์žˆ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ Bean์œผ๋กœ ๋“ฑ๋ก๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‹ค๋งŒ ์ด๋Ÿฐ ์• ๋…ธํ…Œ์ด์…˜์—๋Š” ์ˆœ์ˆ˜ JAVA์—์„œ๋Š” ์ƒ์†๊ด€๊ณ„๋ผ๋Š”๊ฒŒ ์—†๋Š”๋ฐ ์Šคํ”„๋ง์— ์˜ํ•ด์„œ ๊ฐ€๋Šฅํ•ด์ง„ ๊ธฐ๋Šฅ์ด๋ž€ ๊ฒƒ์€ ์ฃผ์˜ํ•˜์ž. ์ˆœ์ˆ˜ JAVA์—์„œ๋„ ํ‘œ์ค€์œผ๋กœ ๋ฐ›์•„๋“ค์ด๋ฉด ์ข‹์€ ๊ธฐ๋Šฅ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

@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)  
  }  
)  

์ž๋™์œผ๋กœ Bean์„ ์Šค์บ”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹น์—ฐํ•˜๊ฒŒ๋„ ๊ฒ€์ƒ‰์—์„œ ์ œ์™ธ๋˜๋Š” Bean๋„ ์ •์˜๋ฅผ ํ•  ์ˆ˜๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์‚ฌ์šฉ๋ฒ•์€ ์–ด๋ ต์ง€ ์•Š๊ฒ ์ง€๋งŒ ๋งŽ์ด ์‚ฌ์šฉ๋˜์ง€๋Š” ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค. ํŠนํžˆ๋‚˜ IncludeFilter์˜ ๊ฒฝ์šฐ๋Š” ๋”์šฑ ๋”.

๋งŒ์•ฝ ์ž๋™ ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์ค‘์— ์ด๋ฆ„ ํ˜น์€ ํƒ€์ž…์ด ๋™์ผํ•œ Bean์ด ์กด์žฌํ•˜์—ฌ ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์ตœ๊ทผ์˜ ์ˆ˜์ • ๊ธฐ์ค€์œผ๋กœ ์ด์•ผ๊ธฐํ•˜์ž๋ฉด ์Šคํ”„๋ง์ด ์ถฉ๋Œ์‹œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ถฉ๋Œ์„ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค. ์ผ๋‹จ์€ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋‹ค.

์ด์ œ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ํ†ตํ•ด Bean์„ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก์‹œ์ผฐ์œผ๋‹ˆ, Bean์„ ์‰ฝ๊ฒŒ ์ฃผ์ž…๋ฐ›๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž.

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

์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…์˜ ๋ฐฉ๋ฒ•์—๋Š” ์•„๋ž˜ ๋„ค ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ์ƒ์„ฑ์ž ์ฃผ์ž…
  • Setter ์ฃผ์ž…
  • ํ•„๋“œ ์ฃผ์ž…
  • ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ์ฃผ์ž…

๋จผ์ € ์•ž์„œ ์ž ๊น ์†Œ๊ฐœํ–ˆ๊ณ  ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•œ๋‹ค. ์ƒ์„ฑ์ž ์ฃผ์ž…์˜ ๊ฒฝ์šฐ ์ฒ˜์Œ Bean์ด ์„ธํŒ…๋˜๋ฉด ๋ถˆ๋ณ€์ด๋‹ค. ์ „๋žต ํŒจํ„ด๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ์ด์ง€๋งŒ ์ด๋Ÿฐ ์œ ์ฆˆ์ผ€์ด์Šค๋Š” ๋งŽ์ด ์•Š์œผ๋ฏ€๋กœ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

@Autowired  
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {  
	this.memberRepository = memberRepository;  
  this.discountPolicy = discountPolicy;  
}  

๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹๋‹ต๊ฒŒ ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” @Autowired๋ฅผ ์ƒ๋žตํ•˜์—ฌ๋„ ์ƒ์„ฑ์ž ์ฃผ์ž…์ด ์ด๋ฃจ์–ด์ง„๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ๋ฌด์กฐ๊ฑด ๊ฐ€๋Šฅํ•œ ๋ช…์‹œ์ ์ธ๊ฒŒ ์ข‹์ง€์•Š๋‚˜ ํ•˜๋Š” ์ƒ๊ฐ์— ๋ถ™์ด๋Š”๊ฑธ ์„ ํ˜ธํ•œ๋‹ค.

๋‹ค์Œ์€ Setter ์ฃผ์ž…์ด๋‹ค. ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‚ฌ์šฉ๋นˆ๋„๋Š” ๋†’์ง€ ์•Š๋‹ค๊ณ  ํ•œ๋‹ค.

private MemberRepository memberRepository;  
  
@Autowired  
public void setMemberRepository(MemberRepository memberRepository) {  
	this.memberRepository = memberRepository;  
}  

โ€œQuestionโ€
์ „๋žต ํŒจํ„ด์ฒ˜๋Ÿผ ๋™์ ์œผ๋กœ ๋‹ค๋ฅธ Bean์„ ์ฃผ์ž…ํ•˜๋ฉด ์œ ์šฉํ•˜์ง€ ์•Š์„๊นŒ? ํ•˜์ง€๋งŒ Bean์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ„ด์ด๊ธฐ ๋•Œ๋ฌธ์— Statelessํ•˜๋‹ค๋Š”๊ฑธ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์–ผ๋งˆ๋‚˜ ์œ ์šฉํ• ๊นŒ ์‹ถ๊ธด ํ•˜๋‹ค. ๋’ค์—์„œ ์†Œ๊ฐœํ•  ์‹ฑ๊ธ€ํ„ด์ด ์•„๋‹Œ ํ”„๋กœํ† ํƒ€์ž… Bean๊ณผ์˜ ์‘์šฉ์— ๋Œ€ํ•ด์„œ๋Š” ์—ฐ๊ตฌํ•ด๋ณผ ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

๋‹ค์Œ์€ ๊ฐ„๊ฒฐํ•œ์˜ ๋ํŒ์™•์ธ ํ•„๋“œ ์ฃผ์ž…์ด๋‹ค. ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž. ๋’ค์— Lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค. ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•œ๋‹ค๋ฉด ์ข‹๋‹ค.

@Component  
public class OrderServiceImpl implements OrderService {  
  
@Autowired  
private MemberRepository memberRepository;	// ๋!  

ํ•„๋“œ ์ฃผ์ž…์€ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ๋„ ์‰ฝ์ง€ ์•Š๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋„ˆ๋ฌด๋‚˜๋„ ๋ช…์‹œ์ ์ด์ง€ ์•Š์œผ๋ฉฐ, DI ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์—†๋‹ค๋ฉด null reference exception์„ ๋งˆ์ฃผํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. Lombok์ด ์—†์œผ๋ฉด ๋ชจ๋ฅด๊ฒ ๋Š”๋ฐ ์žˆ์œผ๋‹ˆ ๋‹จ๋…์œผ๋กœ๋Š” ์‚ฌ์šฉํ•˜์ง€ ๋ง ๊ฒƒ!

๋งˆ์ง€๋ง‰์œผ๋กœ ์ผ๋ฐ˜์ ์ธ ๋ฉ”์†Œ๋“œ์—์„œ๋„ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์‚ฌ์‹ค์ƒ ์›ํ•œ๋‹ค๋ฉด ์–ด๋–ค ํ˜•ํƒœ๋กœ๋“  ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด ์—ญ์‹œ ๋น„์ถ”์ฒœ์ด๋‹ค.

@Autowired  
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {  
	this.memberRepository = memberRepository;  
  this.discountPolicy = discountPolicy;  
}  

โ€œ@Autowired์˜ ์˜ต์…˜โ€
์• ์ดˆ์— ์ด๋Ÿฐ ์˜ต์…˜์ด ์“ฐ์ด์ง€ ์•Š๋Š”๊ฒŒ ์ข‹์„ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐฉ์–ด์ ์ธ ์ฐจ์›์—์„œ ์•Œ์•„๋‘์ž. Optional์€ KOTLIN์˜ null ์ฒ˜๋ฆฌ์ฒ˜๋Ÿผ ์“ธ ์ˆ˜ ์žˆ๋Š” JAVA ๋ฌธ๋ฒ•์ด์ง€๋งŒ ๋” ๊ฐ„๋‹จํ•œ ๋ฌธ๋ฒ•์„ ์›ํ•œ๋‹ค! ์ž๋ฐ”์—๊ฒŒ!

//ํ˜ธ์ถœ ์•ˆ๋จ  
@Autowired(required = false)  
public void setNoBean1(Member member) {  
	System.out.println("setNoBean1 = " + member);  
}  
//null ํ˜ธ์ถœ  
@Autowired  
public void setNoBean2(@Nullable Member member) {  
	System.out.println("setNoBean2 = " + member);  
}  
//Optional.empty ํ˜ธ์ถœ  
@Autowired(required = false)  
public void setNoBean3(Optional<Member> member) {  
	System.out.println("setNoBean3 = " + member);  
}  

์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•ด์„œ Bean์„ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ํ†ตํ•ด์„œ ํ†ต์ง€๋ฅผ ๋ฐ›๋Š”ํŽธ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž ์ฃผ์ž…์ด ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ปดํŒŒ์ผ(์—)๋Ÿฌ ์งฑ! ๊ทธ๋ฆฌ๊ณ  ๋” ์•ˆ์ „ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•˜์—ฌ final ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ€๋ฏธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์€ ๋ถˆ๋ณ€์—๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ)

private final MemberRepository memberRepository;  
private final DiscountPolicy discountPolicy;  
  
@Autowired  
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {  
	this.memberRepository = memberRepository;  
}  

์ด๋Ÿฌํ•œ ํŠน์„ฑ ๋•Œ๋ฌธ์— ์ƒ์„ฑ์ž ์ฃผ์ž…์€ ๊ฐ€์žฅ JAVA ๋ณธ์—ฐ์˜ ๊ธฐ๋Šฅ์„ ์ž˜ ์‚ด๋ฆฐ๋‹ค ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒ์„ฑ์ž ์ฃผ์ž…์ด ๊ถŒ์žฅ๋˜๋Š” ์ด์œ ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ ์ฐฐ๋–ก์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๊นŒ๋„ ์ž ๊น ์–ธ๊ธ‰ํ–ˆ๋˜ Lombok์ด๋‹ค. ์–ด๋–ป๊ฒŒ ํŽธ๋ฆฌํ•ด์ง€๋Š”์ง€ ์ฝ”๋“œ๋กœ ๋ฐ”๋กœ ์‚ดํŽด๋ณด์ž.

@Component  
@RequiredArgsConstructor  
public class OrderServiceImpl implements OrderService {  
   private final MemberRepository memberRepository;  
   private final DiscountPolicy discountPolicy;  
}  

@RequiredArgsConstructor์— ์˜ํ•ด ์ƒ์„ฑ์ž๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค. ์• ๋…ธํ…Œ์ด์…˜์— ์˜ํ•œ ๋ฉ”ํƒ€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์ œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ํ•„๋“œ ์ฃผ์ž…์˜ ํ˜•ํƒœ๋กœ ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ์ƒ์„ฑ์ž ์ฃผ์ž…๋ฐฉ์‹์€ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ์ด-์ง€.

โ€œBean ์ˆ˜๋™ ๋“ฑ๋ก์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐโ€
๋จผ์ € ํ˜ผ๋™ํ•˜์ง€ ๋ง์ž. ์ˆ˜๋™ ๋“ฑ๋ก์€ ์•ž์„œ AppConfig ์•ˆ์—์„œ @Bean ์• ๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ๋“ฑ๋กํ–ˆ๋˜ ๋ฐฉ์‹์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ํŽธํ•œ ์ž๋™์‹œ์Šคํ…œ์ด ์žˆ๋Š”๋ฐ ์ˆ˜๋™์€ ์–ด๋–ค ๊ฒฝ์šฐ์— ํ•„์š”ํ• ๊นŒ? AOP๋ฅผ ํ™œ์šฉํ•œ ๊ธฐ์ˆ ์ง€์› ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ์ˆ˜๋™๋“ฑ๋กํ•˜์—ฌ ์‰ฝ๊ฒŒ ์ฝ”๋“œ ๊ตฌํ˜„๋ถ€๋ฅผ ์ ‘๊ทผํ•˜๋ฉด ์ข‹๋‹ค. ๋ชจ๋“  ์ฝ”๋“œ์˜ ์•ž๋‹จ ๋’ท๋‹จ์—์„œ ์ ์šฉ๋˜๋Š” ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡๋‹ค.

์ž๋™ ์ฃผ์ž…์‹œ ์ถฉ๋Œ ๋ฌธ์ œ

์•„๋ž˜์™€ ๊ฐ™์€ Bean์ด ์ž๋™์ฃผ์ž…๋˜๋ฉด ์–ด๋–ค์ผ์ด ๋ฒŒ์–ด์งˆ๊นŒ?

@Component  
public class FixDiscountPolicy implements DiscountPolicy {}  
  
@Component  
public class RateDiscountPolicy implements DiscountPolicy {}  
  
@Autowired  
private DiscountPolicy discountPolicy;  

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์นœ์ ˆํ•˜๊ฒŒ๋„ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์ค€๋‹ค. ๋‹คํ–‰์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋Ÿฐ ์ถฉ๋Œ์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ? ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ™์ด ์žˆ๋‹ค. ํ•˜๋‚˜ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

๋จผ์ € ํ•„๋“œ ๋ช…์„ Bean ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์Œโ€ฆ๊ทนํ˜์ด๋‹ค(?) ๋ฌธ๋ฒ•๋งŒ์œผ๋กœ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†๋Š” ์ด๋Ÿฐ ๋งค์ง์€ ์ •๋ง์ด์ง€ ์‹ซ๋‹ค. ๊ทผ๋ฐ ์•„๋ฌดํŠผ ๋œ๋‹ค.

@Autowired  
private DiscountPolicy rateDiscountPolicy  

๋‹ค์Œ์€ @qualifier๋ฅผ ํ™œ์šฉํ•ด ๋ช…์‹œ์  ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ƒ์„ฑ๊ณผ ์‚ฌ์šฉ์— ์ด๋ฆ„์„ ๋ถ™์—ฌ์„œ ์ง์„ ๋งž์ถ˜๋‹ค.

@Component  
@Qualifier("mainDiscountPolicy")  
public class RateDiscountPolicy implements DiscountPolicy {}  
  
@Autowired  
public DiscountPolicy setDiscountPolicy(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {  
    return discountPolicy;  
}  

๋‹ค์Œ์€ @Primary ์• ๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ๋™์ž‘์€ ๊ฐ„๋‹จํ•˜๋‹ค. @Primary ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ Bean์ด ์šฐ์„ ์ ์œผ๋กœ ์„ ํƒ๋œ๋‹ค.

@Component  
@Primary  
public class RateDiscountPolicy implements DiscountPolicy {}  
  
@Component  
public class FixDiscountPolicy implements DiscountPolicy {}  

@Primary์™€ @Qualifier๊ฐ€ ํ•จ๊ป˜ ์“ฐ์ด๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ํ•ญ์ƒ ๊ทธ๋ ‡๋“ฏ ๋ช…์‹œ์ ์ธ ๊ฒƒ์ด ์ž๋™๋ณด๋‹ค ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง„๋‹ค. @Qualifier๊ฐ€ ์šฐ์„ ์ ์œผ๋กœ ์“ฐ์ธ๋‹ค. ์ด๋Ÿฐ ์‚ฌํ•ญ์€ ์œ ์ฆˆ์ผ€์ด์Šค๊ฐ€ ์žˆ๋Š”๋ฐ, ๋ฉ”์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ Connector์™€ ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ Connector๊ฐ€ ์žˆ์„ ๋•Œ ๋ฉ”์ธ์— @Primary, ์„œ๋ธŒ์— ํ•„์š”์‹œ @Qualifier๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

Bean์„ ํ™œ์šฉํ•œ ์ „๋žตํŒจํ„ด ๊ตฌํ˜„

์•„๋ž˜ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋ฅผ ์ „๋žตํŒจํ„ด์„ ํ†ตํ•ด ๊ตฌํ˜„ํ•ด๋ณด์ž. discount ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ€ Policy์— ์˜ํ•ด ๊ฒฐ์ •๋  ๊ฒƒ์ด๋‹ค.

@Test  
void findAllBean() {  
    ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);  
  
    DiscountService discountService = ac.getBean(DiscountService.class);  
  
    Member member = new Member(1L, "userA", Grade.VIP);  
    int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");  
  
    assertThat(discountPrice).isEqualTo(1000);  
}  

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜ ์ฝ”๋“œ์—์„œ Map๊ณผ List๋ฅผ ํ†ตํ•ด Bean์„ ๋‹ค๋ฐœ๋กœ ์ „๋‹ฌ๋ฐ›์•„์„œ ์ „๋žตํŒจํ„ด์„ ๊ตฌํ˜„ํ•œ๋‹ค.

โ€œRemindโ€
ํƒ€์ž…์œผ๋กœ Bean์„ ์–ป์–ด์˜ค๋ฉด ๋งค์น˜๋˜๋Š” ๋ชจ๋“  Bean์„ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๊ฒƒ์„ ์ƒ๊ธฐํ•˜์ž!

์ด์ œ ์•„๋ž˜ ์ฝ”๋“œ์—์„œ ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ถ€๋ถ„์„ ์ง‘์ค‘ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

static class DiscountService {  
   private final Map<String, DiscountPolicy> policyMap;  
   private final List<DiscountPolicy> policies;  
  
   public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {  
      this.policyMap = policyMap;  
      this.policies = policies;  
  
      System.out.println("policyMap = " + policyMap);  
      System.out.println("policies = " + policies);  
   }  
  
   public int discount(Member member, int price, String discountCode) {  
      DiscountPolicy discountPolicy = policyMap.get(discountCode);  
  
      System.out.println("discountCode = " + discountCode);  
      System.out.println("discountPolicy = " + discountPolicy);  
      return discountPolicy.discount(member, price);  
   }  
}  

โ€œQuestionโ€
์ €๋ ‡๊ฒŒ String์œผ๋กœ ์ „๋žต์„ ์–ป์–ด์™€์„œ ์‹คํ–‰ํ•˜๋Š”๊ฑธ ์ „๋žตํŒจํ„ด์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ๋” ๊ฐ์ฒด์ง€ํ–ฅ์Šค๋Ÿฌ์šด ๋ฐฉ๋ฒ•์ด ์žˆ์„์ง€ ๋ชจ๋ฅธ๋‹ค. ์—ฐ๊ตฌํ•ด๋ณด์ž.

์‹ค๋ฌด์ ์œผ๋กœ ์ค‘์š”ํ•œ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ Bean ์ž๋™์ฃผ์ž…์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์•˜๋‹ค. ์ œ๋ฒ• ๋ถ„๋Ÿ‰์ด ๋งŽ์•˜๋‹ค. ์ด์ œ๋ถ€ํ„ฐ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ๋œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„๋“ค์„ ์ •๋ฆฌํ•˜๊ณ  ์Šคํ”„๋ง ๊ธฐ๋ณธ์›๋ฆฌ์— ๋Œ€ํ•œ ์ •๋ฆฌ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜์ž!