ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๐Ÿ“Œ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

 : ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฑ 1๊ฐœ๋งŒ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด

 : ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ 2๊ฐœ ์ด์ƒ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์•„์•ผํ•จ (ex. ์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ์„ ์–ธ)

 : (-) ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๋งŽ์ด ๋“ค์–ด๊ฐ„๋‹ค

 : (-) ์˜์กด๊ด€๊ณ„์ƒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์˜์กดํ•œ๋‹ค โžก๏ธ DIP ์œ„๋ฐ˜, OCP ์œ„๋ฐ˜ ๊ฐ€๋Šฅ์„ฑ ๅคš

 : (-) ๊ฒฐ๋ก ์ ์œผ๋กœ ์œ ์—ฐ์„ฑ ↓

 

 

๐Ÿ“Œ ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ

: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๋ฉด์„œ, ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค(1๊ฐœ๋งŒ ์ƒ์„ฑ)์œผ๋กœ ๊ด€๋ฆฌ

: ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ(์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ)

: ์Šคํ”„๋ง ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋นˆ

- ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ์˜ฌ ๋•Œ ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•ด์„œ ํšจ์œจ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ!

 

โ— ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์˜ ์ฃผ์˜์ 

 : ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•ด์„œ ๊ณต์œ ํ•˜๋Š” ์‹ฑ๊ธ€ํ†ค ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ™์€ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€(stateful)ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ฆ‰, ๋ฌด์ƒํƒœ(stateless)๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค!

    - ํŠน์ • ํด๋ผ์ด์–ธํŠธ์— ์˜์กด์ ์ธ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.

    - ํŠน์ • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์•ˆ๋œ๋‹ค.

    - ๊ฐ€๊ธ‰์  ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค.

    - ํ•„๋“œ ๋Œ€์‹ ์— ์ž๋ฐ”์—์„œ ๊ณต์œ ๋˜์ง€ ์•Š๋Š” ์ง€์—ญ๋ณ€์ˆ˜, ํŒŒ๋ผ๋ฏธํ„ฐ, ThreadLocal ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

โ— ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ฑ๊ธ€ํ†ค์„ ๋ณด์žฅํ•ด์ฃผ๋Š” ์ด์œ  - @Configuration๊ณผ ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘

: ์Šคํ”„๋ง์ด CGLIB๋ผ๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ AppConfigํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก!

: ๊ทธ ์ž„์˜์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์‹ฑ๊ธ€ํ†ค์ด ๋ณด์žฅ๋˜๋„๋ก ํ•ด์คŒ!

- @Configuration์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์‹ฑ๊ธ€ํ†ค ๋ณด์žฅ X

 

 

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

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

 

0๏ธโƒฃ AppConfig.java (์„ค์ • ํŒŒ์ผ) ๋งŒ๋“ค๊ธฐ

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

- @ComponentScan ์• ๋…ธํ…Œ์ด์…˜ ๋ถ™์—ฌ์ฃผ๊ธฐ

- excludeFilters๋ฅผ ์ด์šฉํ•ด ์„ค์ • ์ •๋ณด(@Configuration)๋Š” ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์—์„œ ์ œ์™ธ

 

1๏ธโƒฃ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•  ํด๋ž˜์Šค์— @Component ์• ๋…ธํ…Œ์ด์…˜ ๋ถ™์ด๊ธฐ 

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

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

  → ๊ธฐ๋ณธ ์กฐํšŒ ์ „๋žต์€ ํƒ€์ž…์ด ๊ฐ™์€ ๋นˆ์„ ์ฐพ์•„์„œ ์ฃผ์ž… (getBean(MemberRepository.class)์™€ ๋™์ผํ•˜๋‹ค๊ณ  ์ดํ•ด)

- ์Šคํ”„๋ง ๋นˆ์˜ ๊ธฐ๋ณธ ์ด๋ฆ„์€ ํด๋ž˜์Šค๋ช…์„ ์‚ฌ์šฉํ•˜๋˜ ๋งจ ์•ž๊ธ€์ž๋งŒ ์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉ (ex.memberServiceImpl)

*์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„์„ ์ง์ ‘ ์ง€์ •ํ•˜๊ณ  ์‹ถ์œผ๋ฉด

@Component("memberService2")

 

โ•์ปดํฌ๋„ŒํŠธ ์Šค์บ” ํƒ์ƒ‰ ์œ„์น˜

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

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

- ๋งŒ์•ฝ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด @ComponentScan์ด ๋ถ™์€ ์„ค์ • ์ •๋ณด ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€๊ฐ€ ์‹œ์ž‘ ์œ„์น˜!

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

 

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

 - @Component

 - @Controller

 - @Service

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

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

 

 

โ•์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์ œ์™ธํ•  ๋‚˜๋งŒ์˜ ์• ๋…ธํ…Œ์ด์…˜์„ ๋งŒ๋“ค์–ด ๋ณด์ž!

0๏ธโƒฃ ์• ๋…ธํ…Œ์ด์…˜ ๋งŒ๋“ค๊ธฐ

// ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•  ์• ๋…ธํ…Œ์ด์…˜
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {}

 

1๏ธโƒฃ ์›ํ•˜๋Š” ํด๋ž˜์Šค์— ์• ๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ 

@MyExcludeComponent
public class BeanB {}

 

2๏ธโƒฃ ์„ค์ • ํŒŒ์ผ์— ์ ์šฉ

@Configuration
@ComponentScan(
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
static class ComponentFilterAppConfig {}

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

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

 

โœ”๏ธ @Component๋ฉด ์ถฉ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, includeFilters๋ฅผ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์˜ต์…˜์„ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ์Šคํ”„๋ง์˜ ๊ธฐ๋ณธ ์„ค์ •์— ์ตœ๋Œ€ํ•œ ๋งž์ถ”์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ!

 

 

๐Ÿ“Œ ๋นˆ ์ค‘๋… ๋“ฑ๋ก๊ณผ ์ถฉ๋Œ

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

 : ConflictingBeanDefinitionException ์˜ˆ์™ธ ๋ฐœ์ƒ

 

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

 : ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก์ด ์šฐ์„ (์ˆ˜๋™ ๋นˆ์ด ์ž๋™ ๋นˆ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ)

 : ์ตœ๊ทผ ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ๋Š” ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก๊ณผ ์ž๋™ ๋นˆ ๋“ฑ๋ก์ด ์ถฉ๋Œ๋‚˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ!

 

 

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

1๏ธโƒฃ ์ƒ์„ฑ์ž ์ฃผ์ž…

  - ์ƒ์„ฑ์ž ํ˜ธ์ถœ์‹œ์ ์— ๋”ฑ 1๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ

  - ๋ถˆ๋ณ€, ํ•„์ˆ˜ ์˜์กด๊ด€๊ณ„์— ์‚ฌ์šฉ

@Component
public class OrderServiceImpl implements OrderService {
    
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    
    @Autowired // ์ƒ์„ฑ์ž๊ฐ€ ๋”ฑ 1๊ฐœ ์žˆ์œผ๋ฉด @Autowired ์ƒ๋žต ๊ฐ€๋Šฅ!
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

 

๐Ÿ’ก ๊ฒฐ๋ก ์ ์œผ๋กœ, ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•ด์•ผ ๋œ๋‹ค!

 - ๋Œ€๋ถ€๋ถ„์˜ ์˜์กด๊ด€๊ณ„๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ ์ „๊นŒ์ง€ ๋ณ€ํ•˜๋ฉด ์•ˆ๋จ. (๋ถˆ๋ณ€)

 - ์ˆ˜์ •์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด setXxx๋ฉ”์„œ๋“œ๋ฅผ ํ•ญ์ƒ public์œผ๋กœ ์—ด์–ด๋‘์–ด์•ผ ํ•œ๋‹ค. (์ข‹์€ ์„ค๊ณ„ ๋ฐฉ๋ฒ•X)

 - ์ˆ˜์ •์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ˆœ์ˆ˜ํ•œ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒฝ์šฐ ์˜์กด ๊ด€๊ณ„๊ฐ€ ์—†์œผ๋ฉด ์‹คํ–‰์€ ๋˜์ง€๋งŒ ๊ฒฐ๊ณผ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Œ. but ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฃผ์ž… ๋ฐ์ดํ„ฐ๋ฅผ ๋ˆ„๋ฝํ–ˆ์„ ๋•Œ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ!

 

2๏ธโƒฃ ์ˆ˜์ •์ž ์ฃผ์ž…(setter ์ฃผ์ž…)

  - ์„ ํƒ, ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ์˜์กด๊ด€๊ณ„์— ์‚ฌ์šฉ

@Component
public class OrderServiceImpl implements OrderService {

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

*@Autowired์˜ ๊ธฐ๋ณธ ๋™์ž‘์€ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ. ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์–ด๋„ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด @Autowired(required = false)๋กœ ์ง€์ •!

 

3๏ธโƒฃ ํ•„๋“œ ์ฃผ์ž…

  - ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜์ง€๋งŒ ์™ธ๋ถ€์—์„œ ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ํž˜๋“ฌ (์‚ฌ์šฉํ•˜์ง€ ๋ง์ž!)

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

 

4๏ธโƒฃ ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ ์ฃผ์ž…

  - ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ์ฃผ์ž… ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ

 - ์ผ๋ฐ˜์ ์œผ๋กœ ์ž˜ ์‚ฌ์šฉX

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

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

โ• ์˜์กด๊ด€๊ณ„ ์ž๋™ ์ฃผ์ž…์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์Šคํ”„๋ง ๋นˆ์ด์–ด์•ผ ๋™์ž‘. Member๊ฐ™์€ ํด๋ž˜์Šค์—์„œ @Autowired ์ฝ”๋“œ๋ฅผ ์ ์šฉํ•ด๋„ ์•„๋ฌด ๊ธฐ๋Šฅ๋„ ๋™์ž‘ X

 

 

โ— ์ž๋™ ์ฃผ์ž… ๋Œ€์ƒ์„ ์˜ต์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•

  - @Autowired(required = false) : ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด ์ˆ˜์ •์ž ๋ฉ”์„œ๋“œ ์ž์ฒด๊ฐ€ ํ˜ธ์ถœ X

  - org.springframework.lang.@Nullable: ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด null์ด ์ž…๋ ฅ

  - Optional<>: ์ž๋™ ์ฃผ์ž…ํ•  ๋Œ€์ƒ์ด ์—†์œผ๋ฉด Optional.empty๊ฐ€ ์ž…๋ ฅ

// ํ˜ธ์ถœ ์•ˆ๋จ
@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);
}

 

โ— ์ƒ์„ฑ์ž ์ฃผ์ž… ์‹œ final ํ‚ค์›Œ๋“œ

 - ์ƒ์„ฑ์ž์—์„œ ํ˜น์‹œ๋ผ๋„ ๊ฐ’์ด ์„ค์ •๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ๋ง‰์•„์คŒ

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

 

โ”final ํ‚ค์›Œ๋“œ

: ์ƒ์ˆ˜(constant)๋ฅผ ์„ ์–ธํ•˜๋Š” ํ‚ค์›Œ๋“œ

: ์ƒ์ˆ˜๋Š” ํ•œ๋ฒˆ ์ €์žฅํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ X (์„ ์–ธ๊ณผ ๋™์‹œ์— ์ดˆ๊ธฐํ™” ๊ถŒ์žฅ!)

final int PI = 3.14

 

 

๐Ÿ“Œ ๋กฌ๋ณต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

- ๋กฌ๋ณต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” @RequiredArgsConstructor ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด final์ด ๋ถ™์€ ํ•„๋“œ๋ฅผ ๋ชจ์•„์„œ ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด ์คŒ

 

0๏ธโƒฃ build.gradle ์ˆ˜์ •

//lombok ์„ค์ • ์ถ”๊ฐ€ ์‹œ์ž‘ 
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    } 
}
//lombok ์„ค์ • ์ถ”๊ฐ€ ๋

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    
    //lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ ์‹œ์ž‘
    compileOnly 'org.projectlombok:lombok' 
    annotationProcessor 'org.projectlombok:lombok'
    
    testCompileOnly 'org.projectlombok:lombok' 
    testAnnotationProcessor 'org.projectlombok:lombok' 
    //lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€ ๋
    
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    } 
}

- Preferences โžก๏ธ plugin โžก๏ธ lombok ๊ฒ€์ƒ‰ ์„ค์น˜ ์‹คํ–‰ (์žฌ์‹œ์ž‘)

- Preferences โžก๏ธ Annotation Processors โžก๏ธ Enable annotation processing ์ฒดํฌ (์žฌ์‹œ์ž‘)

 

1๏ธโƒฃ ์ฝ”๋“œ ์ˆ˜์ •

- ๊ธฐ์กด

@Component
public class OrderServiceImpl implements OrderService {

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

- ๋กฌ๋ณต ์ ์šฉ ํ›„

@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
}

 

๐Ÿ’ก ์ตœ๊ทผ์—๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋”ฑ 1๊ฐœ ๋‘๊ณ , @Autowired๋ฅผ ์ƒ๋žตํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฃผ๋กœ ์‚ฌ์šฉ. ์—ฌ๊ธฐ์— Lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ @RequiredArgsConstructorํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ๋Šฅ์€ ๋‹ค ์ œ๊ณตํ•˜๋ฉด์„œ, ์ฝ”๋“œ๋Š” ๊น”๋”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ!

 

 

โ— ์กฐํšŒ ๋นˆ์ด 2๊ฐœ ์ด์ƒ์ผ ๋•Œ

: @Autowired๋Š” ํƒ€์ž…(Type)์œผ๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ ํƒ๋œ ๋นˆ์ด 2๊ฐœ ์ด์ƒ์ด๋ฉด NoUniqueBeanDefinitionException ์˜ค๋ฅ˜ ๋ฐœ์ƒ!

→ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์ž!

 

1๏ธโƒฃ @Autowired ํ•„๋“œ ๋ช… ๋งค์นญ

: @Autowired๋Š” ํƒ€์ž… ๋งค์นญ์„ ์‹œ๋„ํ•˜๊ณ , ์ด๋•Œ ์—ฌ๋Ÿฌ ๋นˆ์ด ์žˆ์œผ๋ฉด ํ•„๋“œ ์ด๋ฆ„, ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์œผ๋กœ ๋นˆ ์ด๋ฆ„์„ ์ถ”๊ฐ€ ๋งค์นญํ•จ

// ๊ธฐ์กด ์ฝ”๋“œ
@Autowired
private DiscountPolicy discountPolicy

// ํ•„๋“œ ๋ช…์„ ๋นˆ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ
@Autowired
private DiscountPolicy rateDiscountPolicy

 

2๏ธโƒฃ @Qualifier ์‚ฌ์šฉ

 : ์ถ”๊ฐ€ ๊ตฌ๋ถ„์ž๋ฅผ ๋ถ™์—ฌ์ฃผ๋Š” ๋ฐฉ๋ฒ•. ์ฃผ์ž…์‹œ ์ถ”๊ฐ€์ ์ธ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด์ง€ ๋นˆ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹˜

@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
                      @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
    this.memberRepository = memberRepository;
    this.discountPolicy = discountPolicy;
}

- @Qualifier๋ผ๋ฆฌ ๋งค์นญ

- ๋นˆ ์ด๋ฆ„ ๋งค์นญ (mainDiscountPolicy๋ผ๋Š” ์Šคํ”„๋ง ๋นˆ์„ ์ถ”๊ฐ€๋กœ ๊ฒ€์ƒ‰)

- NoSuchBeanDefinitionException ์˜ˆ์™ธ ๋ฐœ์ƒ

 

3๏ธโƒฃ @Primary ์‚ฌ์šฉ

: ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•. @Autowired ์‹œ์— ์—ฌ๋Ÿฌ ๋นˆ์ด ๋งค์นญ๋˜๋ฉด @Primary๊ฐ€ ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง.

 

๐Ÿ’ก ์ฝ”๋“œ์—์„œ ๋ฉ”์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ปค๋„ฅ์…˜์„ ํš๋“ํ•˜๋Š” ์Šคํ”„๋ง ๋นˆ์ด ์žˆ๊ณ , ๊ฐ€๋” ์‚ฌ์šฉํ•˜๋Š” ์„œ๋ธŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ปค๋„ฅ์…˜์„ ํš๋“ํ•˜๋Š” ์Šคํ”„๋ง ๋นˆ์ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด, ๋ฉ”์ผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ปค๋„ฅ์…˜์„ ํš๋“ํ•˜๋Š” ์Šคํ”„๋ง ๋นˆ์€ @Primary๋ฅผ ์ ์šฉํ•˜๊ณ , ์„œ๋ธŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ๋นˆ์„ ํš๋“ํ•  ๋•Œ๋Š” @Qualifier๋ฅผ ์ง€์ •ํ•ด์„œ ๋ช…์‹œ์ ์œผ๋กœ ํš๋“ํ•˜๋Š” ๋ฐฉ์‹์„ ์ทจํ•˜๋ฉด ์ข‹๋‹ค! (์šฐ์„ ์ˆœ์œ„๋Š” @Primary๋ณด๋‹ค๋Š” @Qualifier๊ฐ€ ๋” ๋†’๋‹ค)

 

 

โ— ์• ๋…ธํ…Œ์ด์…˜์„ ์ง์ ‘ ๋งŒ๋“ค์–ด ๋ณด์ž

: @Qualifier("mainDisxountPolicy")์ด๋ ‡๊ฒŒ ๋ฌธ์ž๋ฅผ ์ ์œผ๋ฉด ์ปดํŒŒ์ผ์‹œ ํƒ€์ž… ์ฒดํฌ๊ฐ€ ๋˜์ง€ ์•Š์Œ!

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}

- ์• ๋…ธํ…Œ์ด์…˜์—๋Š” ์ƒ์†์ด๋ผ๋Š” ๊ฐœ๋…X. ์—ฌ๋Ÿฌ ์• ๋…ธํ…Œ์ด์…˜์„ ๋ชจ์•„์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์Šคํ”„๋ง์ด ์ง€์›ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ!

 

 

โ— ์กฐํšŒํ•œ ๋นˆ์ด ๋ชจ๋‘ ํ•„์š”ํ•  ๋•Œ

public class AllBeanTest {

    @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(discountService).isInstanceOf(DiscountService.class);
        assertThat(discountPrice).isEqualTo(1000);
    }
    
    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);
        } 
    }
}

- new AnnotationConfigApplicationContext()๋ฅผ ํ†ตํ•ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ!

- AutoAppConfig.class, DiscountService.class๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธฐ๋ฉด์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก

  → ๊ทธ๋ž˜์„œ Map<String, DiscountPolicy>์˜ ํ‚ค์— ์Šคํ”„๋ง ๋นˆ์˜ ์ด๋ฆ„, ๊ฐ’์œผ๋กœ DiscountPolicy ํƒ€์ž…์œผ๋กœ ์กฐํšŒํ•œ ๋ชจ๋“  ์Šคํ”„๋ง ๋นˆ์„ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ! 

 

 

๐Ÿ™‹๐Ÿป‍โ™€๏ธ ๊ทธ๋ ‡๋‹ค๋ฉด ์–ธ์ œ ์ˆ˜๋™ ๋นˆ ๋“ฑ๋ก์„ ์‚ฌ์šฉํ•˜๊ณ , ์–ธ์ œ ์ž๋™ ๋นˆ ๋“ฑ๋ก์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ??

๐Ÿ’ก ํŽธ๋ฆฌํ•œ ์ž๋™ ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์ง์ ‘ ๋“ฑ๋กํ•˜๋Š” ๊ธฐ์ˆ  ์ง€์› ๊ฐ์ฒด๋Š” ์ˆ˜๋™ ๋“ฑ๋กํ•˜์ž! ๊ทธ๋ฆฌ๊ณ  ๋‹คํ˜•์„ฑ์„ ์ ๊ทน ํ™œ์šฉํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์ˆ˜๋™ ๋“ฑ๋ก์„ ๊ณ ๋ฏผํ•ด๋ณด์ž!

 

 

๐Ÿ“Œ ๋นˆ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑ

: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ โžก๏ธ ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ โžก๏ธ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… โžก๏ธ ์ดˆ๊ธฐํ™” ์ฝœ๋ฐฑ โžก๏ธ ์‚ฌ์šฉ โžก๏ธ ์†Œ๋ฉธ ์ „ ์ฝœ๋ฐฑ โžก๏ธ ์Šคํ”„๋ง ์ข…๋ฃŒ

 

1๏ธโƒฃ ์ธํ„ฐํŽ˜์ด์Šค(InitalizingBean, DisposableBean) ๊ตฌํ˜„

public class NetworkClient implements InitializingBean, DisposableBean {
    
    private String url;
    
    public NetworkClient() {
        System.out.println("์ƒ์„ฑ์ž ํ˜ธ์ถœ, url = " + url); 
    }
    
    public void setUrl(String url) {
        this.url = url;
    }
    
    //์„œ๋น„์Šค ์‹œ์ž‘์‹œ ํ˜ธ์ถœ
    public void connect() {
        System.out.println("connect: " + url);
    }
    
    public void call(String message) {
        System.out.println("call: " + url + " message = " + message);
    }
    
    //์„œ๋น„์Šค ์ข…๋ฃŒ์‹œ ํ˜ธ์ถœ
    public void disConnect() {
        System.out.println("close + " + url);
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }
    
    @Override
    public void destroy() throws Exception {
        disConnect();
    }
}

- ์Šคํ”„๋ง ์ „์šฉ ์ธํ„ฐํŽ˜์ด์Šค(์ฝ”๋“œ๊ฐ€ ์Šคํ”„๋ง ์ „์šฉ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กด)

- ์ดˆ๊ธฐํ™”, ์†Œ๋ฉธ ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝX

- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ ์šฉX

 

2๏ธโƒฃ ์„ค์ • ์ •๋ณด์— ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ง€์ •

@Configuration
static class LifeCycleConfig {
    
    @Bean(initMethod = "init", destroyMethod = "close")
    public NetworkClient networkClient() {
        NetworkClient networkClient = new NetworkClient();
        networkClient.setUrl("http://hello-spring.dev");
        return networkClient;
    } 
}

- ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ž์œ ๋กญ๊ฒŒ ์ค„ ์ˆ˜ ์žˆ์Œ

- ์Šคํ”„๋ง ๋นˆ์ด ์Šคํ”„๋ง ์ฝ”๋“œ์— ์˜์กดX

- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋„ ์ดˆ๊ธฐํ™”, ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๋ฅผ ์ ์šฉO

 

โ• ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ์ถ”๋ก 

- @Bean์˜ destroyMethod๋Š” ๊ธฐ๋ณธ๊ฐ’์ด (inferred)(์ถ”๋ก )์œผ๋กœ ๋“ฑ๋ก

- close, shutdown๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ

- ์ถ”๋ก  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์‹ซ์œผ๋ฉด destroyMethod="" ์ฒ˜๋Ÿผ ๋นˆ ๊ณต๋ฐฑ์„ ์ง€์ •

 

3๏ธโƒฃ @PostConstruct, @PreDestroy ์• ๋…ธํ…Œ์ด์…˜ ์ง€์› (๊ถŒ์žฅ)

public class NetworkClient {

    // ...
    
    @PostConstruct
    public void init() {
        System.out.println("NetworkClient.init"); connect();
        call("์ดˆ๊ธฐํ™” ์—ฐ๊ฒฐ ๋ฉ”์‹œ์ง€");
    }
    
    @PreDestroy
    public void close() {
        System.out.println("NetworkClient.close");
        disConnect();
    }
}

- ์Šคํ”„๋ง์— ์ข…์†์ ์ธ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ ์ž๋ฐ” ํ‘œ์ค€ (์Šคํ”„๋ง์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ๋™์ž‘)

- ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊ณผ ์ž˜ ์–ด์šธ๋ฆผ

- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ดˆ๊ธฐํ™”, ์ข…๋ฃŒํ•ด์•ผ ํ•˜๋ฉด @Bean์˜ initMethod, destroyMethod๋ฅผ ์‚ฌ์šฉ!

 

 

๐Ÿ“Œ ๋นˆ ์Šค์ฝ”ํ”„

โœ”๏ธ ์‹ฑ๊ธ€ํ†ค : ๊ธฐ๋ณธ ์Šค์ฝ”ํ”„, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ๊ฐ€์žฅ ๋„“์€ ๋ฒ”์œ„์˜ ์Šค์ฝ”ํ”„

 

โœ”๏ธ ํ”„๋กœํ† ํƒ€์ž…

 : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์˜ ์ƒ์„ฑ๊ณผ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…๊นŒ์ง€๋งŒ ๊ด€์—ฌํ•˜๊ณ  ๋”๋Š” ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ๋งค์šฐ ์งง์€ ๋ฒ”์œ„์˜ ์Šค์ฝ”ํ”„

 

 

 

 

 

 

 

- ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•  ๋•Œ ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ

- ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœX

 

โ—์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์ด ์‹ฑ๊ธ€ํ†ค ๋นˆ์ฒ˜๋Ÿผ ๋™์ž‘ - ๋ฌธ์ œ!!

๐Ÿ’ก ์šฐ๋ฆฌ๋Š” ์‹ฑ๊ธ€ํ†ค ๋นˆ๊ณผ ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ, ํ•ญ์ƒ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ํƒ€์ž… ๋นˆ์„ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค! Provider๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค!

@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;

public int logic() {
    PrototypeBean prototypeBean = prototypeBeanProvider.getObject(); // DL
    prototypeBean.addCount();
    int count = prototypeBean.getCount();
    return count;
}

- DL(Dependency Lookup) : ์˜์กด๊ด€๊ณ„๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…(DI) ๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ง์ ‘ ํ•„์š”ํ•œ ์˜์กด๊ด€๊ณ„๋ฅผ ์ฐพ๋Š” ๊ฒƒ

- ObjectProvider : ObjectFactory ์ƒ์†, ์˜ต์…˜, ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ๋“ฑ ํŽธ์˜ ๊ธฐ๋Šฅ์ด ๋งŽ๊ณ , ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•„์š”X. ์Šคํ”„๋ง์— ์˜์กด

โ• ์ด์™ธ์—๋„ ์ž๋ฐ” ํ‘œ์ค€์ธ JSR-330 Provider๊ฐ€ ์žˆ์ง€๋งŒ, ์ฝ”๋“œ๋ฅผ ์Šคํ”„๋ง์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ObjectProvider๋ฅผ ์‚ฌ์šฉํ•˜์ž!

 

โœ”๏ธ ์›น ๊ด€๋ จ ์Šค์ฝ”ํ”„

- ์›น ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์ž‘

- ์Šคํ”„๋ง์ด ํ•ด๋‹น ์Šค์ฝ”ํ”„์˜ ์ข…๋ฃŒ์‹œ์ ๊นŒ์ง€ ๊ด€๋ฆฌ(์ข…๋ฃŒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ)

 - ์›น ์Šค์ฝ”ํ”„ ์ข…๋ฅ˜

    1) request : ์›น ์š”์ฒญ์ด ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐˆ ๋•Œ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„

    2) session : ์›น ์„ธ์…˜์ด ์ƒ์„ฑ๋˜๊ณ  ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„

    3) application : ์›น์˜ ์„œ๋ธ”๋ฆฟ ์ปจํ…์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฒ”์œ„๋กœ ์œ ์ง€๋˜๋Š” ์Šค์ฝ”ํ”„

// ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์ž๋™ ๋“ฑ๋ก
@Scope("prototype")
@Component
public class HelloBean {}
// ์ˆ˜๋™ ๋“ฑ๋ก
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
    return new HelloBean();
}

 

 

โ• ์›น ์š”์ฒญ(request)์ด ์˜ค๋ฉด ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ์˜ˆ์ œ๋ฅผ ๊ฐœ๋ฐœํ•ด๋ณด์ž!

 

0๏ธโƒฃ web ํ™˜๊ฒฝ์ด ๋™์ž‘ํ•˜๋„๋ก build.gradle์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€

//web ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€
implementation 'org.springframework.boot:spring-boot-starter-web'

 

1๏ธโƒฃ MyLogger ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ

@Component
@Scope(value = "request")
public class MyLogger {
    
    private String uuid;
    private String requestURL;
    
    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;        
    }
    
    public void log(String message) {
        System.out.println("[" + uuid + "]" + "[" + requestURL + "] " + message); 
    }
    
    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid + "] request scope bean create:" + this);
    }
    
    @PreDestroy
    public void close() {
        System.out.println("[" + uuid + "] request scope bean close:" + this);
    }
}

- requestURL์€ ์ด ๋นˆ์ด ์ƒ์„ฑ๋˜๋Š” ์‹œ์ ์—๋Š” ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ์™ธ๋ถ€์—์„œ setter๋กœ ์ž…๋ ฅ ๋ฐ›์Œ!

 

2๏ธโƒฃ LogDemoController ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    
    private final LogDemoService logDemoService;
    private final MyLogger myLogger;
    
    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {
        String requestURL = request.getRequestURL().toString();
        myLogger.setRequestURL(requestURL);
        
        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    }     
}

๐Ÿ’ก requestURL์„ MyLogger์— ์ €์žฅํ•˜๋Š” ๋ถ€๋ถ„์€ ์ปจํŠธ๋กค๋Ÿฌ ๋ณด๋‹ค๋Š” ๊ณตํ†ต ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ๋‚˜ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ ๊ฐ™์€ ๊ณณ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ!

 

3๏ธโƒฃ LogDemoService ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ

@Service
@RequiredArgsConstructor
public class LogDemoService {
    
    private final MyLogger myLogger;
    
    public void logic(String id) {
        myLogger.log("service id = " + id);
    } 
}

- ์„œ๋น„์Šค ๊ณ„์ธต์€ ์›น ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๊ณ , ๊ฐ€๊ธ‰์  ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ์ข‹์Œ(์›น๊ณผ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์€ ์ปจํŠธ๋กค๋Ÿฌ๊นŒ์ง€๋งŒ!)

- ์›น๊ณผ ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ request scope์˜ MyLogger์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜์— ์ €์žฅํ•ด์„œ ์ฝ”๋“œ์™€ ๊ณ„์ธต์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€!

 

โ— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์—์„œ ์‹ฑ๊ธ€ํ†ค ๋นˆ์€ ์ƒ์„ฑํ•ด์„œ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, request ์Šค์ฝ”ํ”„ ๋นˆ์€ ์•„์ง ์ƒ์„ฑX(์‹ค์ œ ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ์™€์•ผ ์ƒ์„ฑ ๊ฐ€๋Šฅ!)

    โžก๏ธ ์˜ค๋ฅ˜ ๋ฐœ์ƒ

 

โ• ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์ž!

โœ”๏ธ Provider ์‚ฌ์šฉ

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    
    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider; // ๋‹ฌ๋ผ์ง„ ๋ถ€๋ถ„
    
    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {
        String requestURL = request.getRequestURL().toString();
        MyLogger myLogger = myLoggerProvider.getObject(); // ๋‹ฌ๋ผ์ง„ ๋ถ€๋ถ„
        myLogger.setRequestURL(requestURL);
        
        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    } 
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
    
    private final ObjectProvider<MyLogger> myLoggerProvider; // ๋‹ฌ๋ผ์ง„ ๋ถ€๋ถ„
    
    public void logic(String id) {
        MyLogger myLogger = myLoggerProvider.getObject(); // ๋‹ฌ๋ผ์ง„ ๋ถ€๋ถ„
        myLogger.log("service id = " + id);
    } 
}

- ObjectProvider ๋•๋ถ„์— ObjectProvider.getObject()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ๊นŒ์ง€ request scope ๋นˆ์˜ ์ƒ์„ฑ์„ ์ง€์—ฐํ•  ์ˆ˜ ์žˆ์Œ

- ObjectProvider.getObject()๋ฅผ LogDemoController, LogDemoService์— ๊ฐ๊ฐ ํ•œ๋ฒˆ์”ฉ ๋”ฐ๋กœ ํ˜ธ์ถœํ•ด๋„ ๊ฐ™์€ HTTP ์š”์ฒญ์ด๋ฉด ๊ฐ™์€ ์Šคํ”„๋ง ๋นˆ์ด ๋ฐ˜ํ™˜!

 

โœ”๏ธ ํ”„๋ก์‹œ ์‚ฌ์šฉ

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) // ํ•ต์‹ฌ!
public class MyLogger {
   // ...
}

- ์ ์šฉ ๋Œ€์ƒ์ด ํด๋ž˜์Šค๋ฉด TARGET_CLASS, ์ธํ„ฐํŽ˜์ด์Šค๋ฉด INTERFACES๋ฅผ ์„ ํƒ

- MyLogger์˜ ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‘๊ณ  HTTP request์™€ ์ƒ๊ด€ ์—†์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋‹ค๋ฅธ ๋นˆ์— ๋ฏธ๋ฆฌ ์ฃผ์ž…ํ•ด ๋‘˜ ์ˆ˜ ์žˆ์Œ!

 

๐Ÿ™‹๐Ÿป‍โ™€๏ธ ์ด๊ฒŒ ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ•œ๊ฑธ๊นŒ?

 : CGLIB(๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๋กœ ๋‚ด ํด๋ž˜์Šค(MyLogger)๋ฅผ ์ƒ์† ๋ฐ›๋Š” ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด(ex. MyLogger$$EnhancerBySpringCGLIB)๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฃผ์ž…

 : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— "myLogger"๋ผ๋Š” ์ด๋ฆ„ ๋Œ€์‹ ์— ์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋“ฑ๋ก

 : ac.getBean("myLogger", MyLogger.class)๋กœ ์กฐํšŒํ•ด๋„ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์กฐํšŒ๋จ

 

โœ”๏ธ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ ๋‚ด๋ถ€์—์„œ ์ง„์งœ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ ๋กœ์ง์ด ๋“ค์–ด์žˆ์Œ

   - ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋‚ด๋ถ€์— ์ง„์งœ myLogger๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Œ

   - ํด๋ผ์ด์–ธํŠธ๊ฐ€ myLogger.log()์„ ํ˜ธ์ถœํ•˜๋ฉด ์‚ฌ์‹ค์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒƒ

  - ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” request ์Šค์ฝ”ํ”„์˜ ์ง„์งœ myLogger.log()๋ฅผ ํ˜ธ์ถœ

   - ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์›๋ณธ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ๋Š” ์‚ฌ์‹ค ์›๋ณธ์ธ์ง€ ์•„๋‹Œ์ง€๋„ ๋ชจ๋ฅด๊ฒŒ, ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค(๋‹คํ˜•์„ฑ)

 

 

๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/07   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ