Skip to content

choiseoji/spring-tutorial-20th

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

12 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

spring-tutorial-20th

1๏ธโƒฃย ์Šคํ”„๋ง์˜ ๋‹ค์–‘ํ•œ ๊ธฐ์ˆ ๋“ค

1. IoC : Inversion of Control (์ œ์–ด์˜ ์—ญ์ „)

public class Car {

    Tire tire;

    public Car() {
        tire = new KoreaTire();
    }

    public void introduceTire() {
        tire.introduce();
    }
}

interface Tire {
    void introduce();
}

class KoreaTire() {

    public void introduce() {
        System.out.println("๋‚˜๋Š” ํ•œ๊ตญ ํƒ€์ด์–ด์•ผ");
    }
}

class AmericaTire() {

    public void introduce() {
        System.out.println("๋‚˜๋Š” ๋ฏธ๊ตญ ํƒ€์ด์–ด์•ผ");
    }
}

์œ„์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด Car ํด๋ž˜์Šค๋Š” Tire ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋ฅผ Car ํด๋ž˜์Šค๊ฐ€ Tire ํด๋ž˜์Šค๋ฅผ ์˜์กดํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค.

ํ•˜์ง€๋งŒ Car ํด๋ž˜์Šค๋Š” ๋ณธ์ธ์˜ ๋กœ์ง์— ๋Œ€ํ•œ ์ฑ…์ž„๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Tire ํด๋ž˜์Šค์˜ ๊ตฌํ˜„์— ๋Œ€ํ•œ ์ฑ…์ž„ ๋˜ํ•œ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค (= ๋‘ ํด๋ž˜์Šค์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ๊ฐ•ํ•˜๋‹ค)

โ‡’ Car ํด๋ž˜์Šค๋Š” Tire ํด๋ž˜์Šค์˜ ๊ตฌํ˜„ ์ฑ…์ž„์„ ์ง€๋Š” ๊ฒƒ์ด ๋ถ€๋‹ด์Šค๋Ÿฌ์›Œ ์ œ 3์ž์—๊ฒŒ ์˜์กด๊ด€๊ณ„์— ๋Œ€ํ•œ ์ฑ…์ž„์„ ์œ„์ž„ํ•˜๊ณ ์ž ํ•œ๋‹ค. ์ด๋ฅผ IoC, ์ œ์–ด์˜ ์—ญ์ „์ด๋ผ๊ณ  ๋งํ•œ๋‹ค.


public class Select() {
    
    public Car car() {
        return new Car();
    }

    public Tire tire() {
		    // return new KoreaTire();
        return new AmericaTire();
    }
}

public class Car {

    Tire tire;

    public Car() {
        tire = new Select().tire();
    }

    // ...์ดํ•˜ ๋™์ผ ..
}

์œ„์™€ ๊ฐ™์ด Select๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์–ด๋–ค tire๋ฅผ ๋„˜๊ฒจ์ค„์ง€์— ๋Œ€ํ•œ ์ฑ…์ž„์„ ์œ„์ž„ํ•œ๋‹ค.

Car ํด๋ž˜์Šค๋Š” Select๊ฐ€ ๋ฐ˜ํ™˜ํ•ด์ค€ tire๋งŒ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ถ”ํ›„์— KoreaTire๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ํ•ด๋„ Car ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ Select ํด๋ž˜์Šค์˜ tire์— ๋Œ€ํ•œ return ๋ถ€๋ถ„๋งŒ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ Car๋Š” Tire์˜ ์ฑ…์ž„์— ๋Œ€ํ•œ ๋ถ„๋ฆฌ๋ฅผ ์ด๋ฃจ์—ˆ๋‹ค!


๐Ÿšจย ํ•˜์ง€๋งŒ ์•„์ง Select ํด๋ž˜์Šค๋Š” Tire ์— ๋Œ€ํ•ด์„œ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜์ง€ ๋ชป ํ•œ๊ฑฐ ์•„๋‹Œ๊ฐ€์š”??

์‚ฌ์‹ค ์Šคํ”„๋ง์—์„œ ์ œ๊ณตํ•˜๋Š” IoC ์ปจํ…Œ์ด๋„ˆ๋Š” Select ํด๋ž˜์Šค๊ฐ€ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ๋Š” ์˜์กด์„ฑ ๊ด€๋ฆฌ์™€ ๊ฐ์ฒด ์„ ํƒ ๊ธฐ๋Šฅ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.


IoC ์ปจํ…Œ์ด๋„ˆ

๊ฐ์ฒด์˜ ์ƒ์„ฑ๊ณผ ์˜์กด์„ฑ ์ฃผ์ž…, ๊ด€๋ฆฌ, ์†Œ๋ฉธ์„ ๋‹ด๋‹นํ•˜๋Š” ์ค‘์•™ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ด๋‹ค.

  • ๋นˆ(Bean) ๊ด€๋ฆฌ
    • IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด(๋นˆ)๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•œ๋‹ค.
    • ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ๋ถ€๋ถ„์„ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  • ์˜์กด์„ฑ ์ฃผ์ž… (Dependency Injection)
    • IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ๋นˆ ๊ฐ„์˜ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•œ๋‹ค.
    • โ‡’ ๊ฐ์ฒด ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ , ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.
  • ๋ผ์ดํ”„์‚ฌ์ดํด ๊ด€๋ฆฌ
    • IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ๋นˆ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์ดˆ๊ธฐํ™”์™€ ์†Œ๋ฉธ ์‹œ์ ์— ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์„ค์ • ๊ด€๋ฆฌ
    • Spring IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •์„ ๊ด€๋ฆฌํ•˜๊ณ , XML, Java ์„ค์ • ํด๋ž˜์Šค, ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์˜ ์„ค์ •์„ ์ง€์›ํ•œ๋‹ค.
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-07 แ„‹แ…ฉแ„’แ…ฎ 4 19 58

IoC ์ปจํ…Œ์ด๋„ˆ๋Š” DI ํŒจํ„ด์„ ํ†ตํ•ด ๊ฐ์ฒด ๊ฐ„์˜ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ

๊ทธ๋Ÿผ ์ด์ œ DI ํŒจํ„ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž!


2. DI : Dependency Injection (์˜์กด์„ฑ ์ฃผ์ž…)

๊ฐ์ฒด๊ฐ„์˜ ์˜์กด์„ฑ์„ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์„ ๋งํ•˜๋ฉฐ, ๊ตฌ์ฒด์ ์ธ ์˜์กด ์˜ค๋ธŒ์ ํŠธ์™€ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ฃผ์ฒด๋ฅผ ๋Ÿฐํƒ€์ž„ ์‹œ์— ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์ž‘์—…์„ ๋งํ•œ๋‹ค.


์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ์„ธ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

1) ์ƒ์„ฑ์ž ์ฃผ์ž…

  • ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ๋ชจ๋“  ์˜์กด์„ฑ์ด ์ฃผ์ž…๋˜์–ด ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.
@Component
public class Car {

    private Tire tire;
		
		@Autowired
    public Car(@Qualifier("koreaTire") Tire tire) {
        this.tire = tire;
    }
}
@Component
@RequiredArgsConstructor
public class Car {

    private final Tire tire;
		
}

์ฒซ๋ฒˆ์งธ ์ฝ”๋“œ์™€ ๋‘๋ฒˆ์งธ ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ์ƒ์„ฑ์ž ์ฃผ์ž…์˜ ์˜ˆ์‹œ ์ฝ”๋“œ์ธ๋ฐ @RequiredArgsConstructor ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด final๋กœ ์„ ์–ธํ•œ ํ•„๋“œ์™€ @NonNull ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํ•„๋“œ์— ๋Œ€ํ•ด์„œ ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.


2) Setter ์ฃผ์ž…

  • ์„ ํƒ์  ์˜์กด์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๊ณ , ๊ฐ์ฒด ์ƒ์„ฑ ์ดํ›„์—๋„ ์˜์กด์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ์˜์กด์„ฑ์ด ์ฃผ์ž…๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ๋„ ๊ฐ์ฒด ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์ด ๊ฐ•์ œ๋˜์ง€ ์•Š๋Š” ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.
public class Car {
    private Tire tire;

    // Setter ์ฃผ์ž…
    public void setTire(Tire tire) {
        this.tire = tire;
    }
}
// ..์™ธ๋ถ€ ์ฝ”๋“œ..
Tire tire = new KoreaTire();
Car car = new Car();
car.setTire(tire);    // setter ์ฃผ์ž…

3) ํ•„๋“œ ์ฃผ์ž…

  • ์Šคํ”„๋ง์ด ์ง์ ‘ ํ•„๋“œ์— ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • ์˜์กด์„ฑ์ด ์™ธ๋ถ€์— ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด์˜ ์˜์กด์„ฑ์„ ํŒŒ์•…ํ•˜๊ธฐ ํž˜๋“ค๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.
@Component
public class Car {

    @Autowired
    @Qualifier("koreaTire")
    private Tire tire;
}

@Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„๋“œ ์ฃผ์ž…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. Car ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ tire๋Š” ์ž๋™์œผ๋กœ ์Šคํ”„๋ง IoC ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด ์ฃผ์ž…๋œ๋‹ค.

koreaTire, americaTire์™€ ๊ฐ™์ด ๊ฐ™์€ ํƒ€์ž…์˜ ๋นˆ์ด ์žˆ์„ ๋•Œ, ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋นˆ์„ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•ด @Qualifier ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์ž…ํ•˜๊ณ ์ž ํ•˜๋Š” ๋นˆ์˜ ์ด๋ฆ„์„ ๋ช…์‹œํ•ด์ค€๋‹ค.


๐Ÿ’กย ์„ธ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ๊ถŒ์žฅํ•œ๋‹ค.

  • ๋ถˆ๋ณ€์„ฑ ์œ ์ง€
    • ์ƒ์„ฑ์ž ์ฃผ์ž…์€ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ๋ชจ๋“  ์˜์กด์„ฑ์ด ๋ฐ˜๋“œ์‹œ ์ œ๊ณต๋œ๋‹ค.
    • ๊ฐ์ฒด ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•˜๊ณ , ๊ฐ์ฒด์˜ ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•„์ˆ˜ ์˜์กด์„ฑ ์ฃผ์ž… ๋ณด์žฅ
    • ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, ๋ชจ๋“  ์˜์กด์„ฑ์„ ๋ชจ๋‘ ๋ฐ›์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด์„ฑ์„ ๋นผ๋จน์„ ๊ฐ€๋Šฅ์„ฑ์ด ์—†๋‹ค.
    • (setter ์ฃผ์ž… ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” setter ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ์ฒด ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ ์˜์กด์„ฑ์„ ๋นผ๋จน์„ ์ˆ˜ ์žˆ๋‹ค)
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ
    • ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›๋Š” ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๋ชจํ‚นํ•  ์ˆ˜ ์žˆ๋‹ค.

3. AOP : Aspect Oriented Programming (๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ)

์–ด๋–ค ๋กœ์ง์„ ๊ธฐ์ค€์œผ๋กœ ํ•ต์‹ฌ์ ์ธ ๊ด€์ , ๋ถ€๊ฐ€์ ์ธ ๊ด€์ ์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ๋ณด๊ณ  ๊ทธ ๊ด€์ ์„ ๊ธฐ์ค€์œผ๋กœ ๊ฐ๊ฐ ๋ชจ๋“ˆํ™”ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

  • ํ•ต์‹ฌ ๊ด€์‹ฌ์‚ฌ : ์šฐ๋ฆฌ๊ฐ€ ์ ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
  • ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ : ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์— ๊ณตํ†ต์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๋กœ์ง
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-05 แ„‹แ…ฉแ„’แ…ฎ 4 31 26

์œ„์˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋…ธ๋ž€ ๋ธ”๋ก, ๋นจ๊ฐ„ ๋ธ”๋ก, ํŒŒ๋ž€ ๋ธ”๋ก์ด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

์ด๋Š” ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์—์„œ ์ค‘๋ณต๋˜๋Š” ๋ฉ”์†Œ๋“œ, ํ•„๋“œ, ์ฝ”๋“œ ๋“ค์ด ๋‚˜ํƒ€๋‚œ๋‹ค๋Š” ๋œป์ด๋‹ค. ๋งŒ์•ฝ ํด๋ž˜์Šค A์˜ ์ฃผํ™ฉ ๋ธ”๋ก์„ ์ˆ˜์ •ํ•œ๋‹ค๋ฉด ํด๋ž˜์Šค B,C์˜ ์ฃผํ™ฉ ๋ธ”๋ก๋„ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค˜์•ผ ๋  ๊ฒƒ์ด๋‹ค. โ†’ ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ ์ข‹์ง€ ์•Š์Œ

์ด์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์งœ๋‹ค๋ณด๋ฉด ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ๊ณ„์† ๋ฐ˜๋ณตํ•ด์„œ ์“ฐ๋Š” ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด๋ฅผ โ€˜ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ (Crosscutting Concerns)โ€™๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค


AOP๋Š” aspect๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

โ†’ ์ด๋Ÿฐ ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ๋ฅผ Aspect๋กœ ๋ชจ๋“ˆํ™”ํ•˜๊ณ  ํ•ต์‹ฌ์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ๋ถ„๋ฆฌํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด AOP์˜ ์ทจ์ง€์ด๋‹ค


AOP์˜ ์ฃผ์š” ํ‚ค์›Œ๋“œ

  • Aspect : ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์“ฐ์ด๋Š” ๊ณตํ†ต ๋ถ€๋ถ„ ์ฝ”๋“œ๋ฅผ ๋ชจ๋“ˆํ™”ํ•œ ๊ฒƒ
  • Target : Aspect๊ฐ€ ์ ์šฉ๋˜๋Š” ๊ณณ
  • Advice : Aspect์—์„œ ์‹ค์งˆ์ ์ธ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด
  • Joint Point: Advice๊ฐ€ Target์— ์ ์šฉ๋˜๋Š” ์‹œ์ 
  • Point Cut : Joint Point์˜ ์ƒ์„ธ ์ŠคํŽ™์„ ์ •์˜ํ•œ ๊ฒƒ

๊ทธ๋Ÿผ ์ด์ œ ํ•œ๋ฒˆ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉฐ ์ดํ•ดํ•ด๋ณด์ž.

์‹คํ–‰ ์‹œ๊ฐ„ ์ถœ๋ ฅํ•˜๊ธฐ

@Service
public class TodoService() {

    // todo ์ƒ์„ฑ
	public void createTodo(TodoReq todoReq) {
		long begin = System.currentTimeMillis();
		try{
			todoRepository.save(todoReq);
		} finally {
			System.out.println(System.currentTimeMillis() - begin);
		}
	}

    // todo ์‚ญ์ œ
    public void deleteTodo(Long id) {
        long begin = System.currentTimeMillis();
		try{
			todoRepository.deleteById(id);
		} finally {
			System.out.println(System.currentTimeMillis() - begin);
		}
    }
}

์ด๋ ‡๊ฒŒ todo๋ฅผ ์ƒ์„ฑ, ์‚ญ์ œํ•˜๋Š” ์ฝ”๋“œ์— ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ณ  ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์ค‘๋ณต์ด ๋œ๋‹ค.

์ง€๊ธˆ์€ ๋ฉ”์„œ๋“œ๊ฐ€ 2๊ฐœ๋งŒ ์กด์žฌํ•˜๋Š” ์ƒํ™ฉ์ด๋ผ ๊ดœ์ฐฎ์•„ ๋ณด์ด์ง€๋งŒ ๋งŒ์•ฝ ๋ฉ”์„œ๋“œ๊ฐ€ ์—„์ฒญ ๋งŽ๋‹ค๋ฉด, ์—„์ฐฝ๋‚˜๊ฒŒ ๋งŽ์€ ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

โ‡’ AOP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊ฐœ์„ ํ•ด๋ณด์ž!


๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•  Aspect ์ž‘์„ฑ

@Aspect
@Component
public class Performance() {

    @Around("execution(* com.example.todo.TodoService.*(..))")
    public Object countTime(ProceedingJoinPoint joinPoint) throws Throwable {
		    // ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ 
        long begin = System.currentTimeMillis();
        
        // ๋ฉ”์„œ๋“œ ์‹คํ–‰
        Object proceed = joinPoint.proceed();
        
        // ๋ฉ”์„œ๋“œ ์‹คํ–‰ ํ›„
        System.out.println(System.currentTimeMillis() - begin);
        return proceed;
    }
}
  • @Aspect ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ AOP์˜ Aspect์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. โ†’ @Component ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ Aspect ํด๋ž˜์Šค๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ๋ถ€ํ„ฐ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•œ๋‹ค (AOP์™€ IoC์˜ ๊ด€๊ณ„)
  • @Around ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•œ๋‹ค
    • execution(* com.example.todo.TodoService.*(..)) : TodoService ํด๋ž˜์Šค์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด Aspect๋ฅผ ์ ์šฉํ•œ๋‹ค
    • execution(* com.example.todo.TodoService.createTodo(..)) : createTodo ๋ฉ”์„œ๋“œ์—๋งŒ Aspect๋ฅผ ์ ์šฉํ•œ๋‹ค
  • ProceedingJoinPoint ๋Š” ํ˜ธ์ถœ๋œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ์‹ธ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค
    • proceed()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์‹คํ–‰๋œ๋‹ค

์ด๋ ‡๊ฒŒ Aspect๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ๋ถ„๋ฆฌ๊ฐ€ ๋˜๋ฏ€๋กœ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋˜๊ณ , ์žฌ์‚ฌ์šฉ์„ฑ์ด ์ข‹์•„์ง„๋‹ค.


4. PSA : Portable Service Abstraction

ํ™˜๊ฒฝ์˜ ๋ณ€ํ™”์™€ ๊ด€๊ณ„์—†์ด ์ผ๊ด€๋œ ๋ฐฉ์‹์˜ ๊ธฐ์ˆ ๋กœ์˜ ์ ‘๊ทผ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•˜๋Š” ์ถ”์ƒํ™” ๊ตฌ์กฐ์ด๋‹ค.

์šฐ๋ฆฌ๋Š” JDBC Driver๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์ง€๋งŒ JDBC Driver๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š”์ง€๋Š” ๋ชจ๋ฅธ๋‹ค.

์ด๋ ‡๊ฒŒ ์‹ค์ œ ๊ตฌํ˜„๋ถ€๋ฅผ ๋ชจ๋ฅด๋”๋ผ๋„ ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์„œ๋น„์Šค ์ถ”์ƒํ™”์ด๋‹ค.


๊ทธ๋ ‡๋‹ค๋ฉด Portableํ•œ ์„œ๋น„์Šค ์ถ”์ƒํ™”๋Š” ๋ญ˜๊นŒ?

PSA๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ถ”์ƒํ™” ๊ณ„์ธต์„ ๊ตฌํ˜„ํ•œ ๋˜ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋กœ ๊ต์ฒด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ๋งํ•œ๋‹ค.

@Controller
public class MemberController {

		@GetMapping("/info")
		public void getInfo() {
				// ...
		}
}
@Controller
public class MemberController {

		@RequestMapping(value="/info", method=RequestMethod.GET)
		public void getInfo() {
				// ...
		}
}

์›ํ•˜๋Š” url๋กœ ๋งคํ•‘ํ•˜๊ณ  ์‹ถ์„ ๋•Œ @GetMapping, @RequestMapping(method=RequestMethod.GET) ๋‘˜ ์ค‘ ์•„๋ฌด๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•ด๋„ ๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , http url ๋งคํ•‘์ด ์ถ”์ƒํ™” ๋˜์–ด์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์„œ๋น„์Šค๋กœ ๊ต์ฒด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— PSA๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. (@GetMapping์—์„œ @RequestMapping์œผ๋กœ)



2๏ธโƒฃย SpringBean ์ด๋ž€?

Spring Bean ๐Ÿซ›

: ์Šคํ”„๋ง IoC ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๋งํ•œ๋‹ค


SpringBean์˜ ์ƒ๋ช…์ฃผ๊ธฐ

๋นˆ์ด ์ƒ์„ฑ๋˜๊ณ  ์‚ฌ์šฉ๋œ ํ›„ ์†Œ๋ฉธ๋˜๋Š” ์ „์ฒด ๊ณผ์ •์„ ์˜๋ฏธํ•œ๋‹ค

๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•˜๋ฉด โ€œ๊ฐ์ฒด ์ƒ์„ฑ โ†’ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…โ€ ์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ฐ€์ง„๋‹ค.


1) ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ

// ๊ตฌ์„ฑ, ์„ค์ • ์ •๋ณด
@Configuration
public class AppConfig {
	
	// ...
}

public class SpringContainerExample {

    public static void main(Stirng[] args) {

        // ApplicationContext(์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ) ์ƒ์„ฑ
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 1 30 15

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์ธ ApplicationContext๊ฐ€ ์Šคํ”„๋ง ๋นˆ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

AnnotationConfigApplicationContext() ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋•Œ, ๊ตฌ์„ฑ์ •๋ณด ํด๋ž˜์Šค์ธ AppConfig.class๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•ด์ค€๋‹ค (โ†’ ์Šคํ”„๋ง๋ถ€ํŠธ ์—†์ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ• ๋•Œ ์ง์ ‘ config๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ๋‹ค๊ณ  ํ•œ๋‹ค)


2) ๋นˆ ๋“ฑ๋ก

// AppConfig.class

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

@Bean
public MemberRepository memberRepository() {
    return new MemoryMemberRepository();
}
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 1 32 24

์ „๋‹ฌ๋ฐ›์€ AppConfig๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•ด์ค๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ๋นˆ์˜ ์ด๋ฆ„์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.


3) ์˜์กด์„ฑ ์ฃผ์ž…

AppConfig ๋‚ด์šฉ์„ ์ฐธ๊ณ ํ•ด ์˜์กด๊ด€๊ณ„๋ฅผ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๋ฉด, ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์ผ์–ด๋‚œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 1 34 37

AppConfig๋ฅผ ๋ณด๋ฉด memberService ๋ฉ”์„œ๋“œ์—์„œ memberRepository๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ง์€ โ€œmemberService๊ฐ€ memberRepository๋ฅผ ์˜์กดํ•œ๋‹คโ€๋ผ๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


4) ์ดˆ๊ธฐํ™”

์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์ด ์™„๋ฃŒ๋˜๋ฉด, ์Šคํ”„๋ง์€ ์Šคํ”„๋ง ๋นˆ์—๊ฒŒ ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™” ์‹œ์ ์„ ์•Œ๋ ค์ค€๋‹ค.

์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” ์ดˆ๊ธฐํ™” ์ž‘์—…์ด๋ž€? ์ฃผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ, ๋ฆฌ์†Œ์Šค ์ดˆ๊ธฐํ™” ๋“ฑ ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋˜๊ธฐ ์ „์— ํ•„์š”ํ•œ ์ž‘์—… ๋“ฑ์„ ์˜๋ฏธํ•œ๋‹ค.

@PostConstruct
public void init() {
    System.out.println("๋นˆ ์ดˆ๊ธฐํ™”");
    // .. ์ดˆ๊ธฐํ™” ๋กœ์ง ..
}

@PostConstruct ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ํ›„ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์ค€๋‹ค.


5) ๋นˆ ์‚ฌ์šฉ

๋นˆ์˜ ์ดˆ๊ธฐํ™”๊นŒ์ง€ ์™„๋ฃŒ๋˜๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋นˆ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋นˆ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์„œ๋น„์Šค์™€ ์ƒํ˜ธ์ž‘์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


6) ์†Œ๋ฉธ

์Šคํ”„๋ง์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ์ง์ „์— ์†Œ๋ฉธ ์ฝœ๋ฐฑ์„ ์ค€๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜, ๋นˆ์ด ๋” ์ด์ƒ ํ•„์š” ์—†์„๋•Œ ์†Œ๋ฉธ๋ฉ๋‹ˆ๋‹ค.

@PreDestroy
public void destroy() {
    System.out.println("๋นˆ ์†Œ๋ฉธ");
    // .. ์†Œ๋ฉธ ๋กœ์ง..
}

@PreDestroy ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ์ง์ „์— ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์ค€๋‹ค.


7) ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜๋ฉด, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์ž์‹ ์ด ๊ด€๋ฆฌํ•˜๋Š” ๋ชจ๋“  ๋นˆ์„ ์†Œ๋ฉธ์‹œํ‚ค๊ณ  ๋ฆฌ์†Œ์Šค๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.



3๏ธโƒฃย Annotation ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž

Annotation ์ด๋ž€?

์ž๋ฐ”์—์„œ ์ฝ”๋“œ ์‚ฌ์ด์— ํŠน๋ณ„ํ•œ ์˜๋ฏธ, ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๊ธฐ์ˆ ์„ ๋งํ•œ๋‹ค.

ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ, ํ•„๋“œ ๋“ฑ์˜ ์š”์†Œ์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋™์ž‘ ๋ฐฉ์‹์„ ์ •์˜ํ•œ๋‹ค. ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์Šคํ”„๋ง์€ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


์–ด๋…ธํ…Œ์ด์…˜ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {

		// ..๊ตฌํ˜„ ๋‚ด์šฉ
}
  • @Target
    • ์–ด๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์š”์†Œ์˜ ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.
    • ElementType.PARAMETER ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค
    • ElementType.TYPE : ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค, ์—ด๊ฑฐํ˜•, ์–ด๋…ธํ…Œ์ด์…˜ ํƒ€์ž…์— ์ ์šฉ๋œ๋‹ค
    • ElementType.METHOD : ๋ฉ”์„œ๋“œ์— ์ ์šฉ๋œ๋‹ค
    • ElementType.FIELD : ํด๋ž˜์Šค์˜ ํ•„๋“œ์— ์ ์šฉ๋œ๋‹ค
  • @Retention
    • ์–ด๋…ธํ…Œ์ด์…˜์˜ ์œ ์ง€ ๊ธฐ๊ฐ„์„ ์ •์˜ํ•œ๋‹ค.
    • RetentionPolicy.RUNTIME ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด runtime์—๋„ ์œ ์ง€ ๋จ์„ ์˜๋ฏธํ•œ๋‹ค โ‡’ ์ด ์–ด๋…ธํ…Œ์ด์…˜์€ ์‹คํ–‰ ์ค‘์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด reflection์„ ํ†ตํ•ด ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • RetentionPolicy.SOURCE : ์ปดํŒŒ์ผ ์‹œ์ ์—๋งŒ ์œ ์ง€
    • RetentionPolicy.CLASS : ์ปดํŒŒ์ผ ํ›„, ํด๋ž˜์Šค ํŒŒ์ผ์— ํฌํ•จ๋˜์ง€๋งŒ ๋Ÿฐํƒ€์ž„์—๋Š” ์œ ์ง€๋˜์ง€ ์•Š์Œ
  • @interface
    • ์ž๋ฐ”์—์„œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ• ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

@RestController
public class MyController {

    @GetMapping("/user")
    public String getUser(@Login String userId) {
        
        // .. ๊ตฌํ˜„ ๋‚ด์šฉ
        return (userId);
    }
}

ํ˜„์žฌ @Login ์ด๋ผ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ–ˆ๊ณ , ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

userId ๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์— ํŠน์ˆ˜ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.


์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—๊ฒŒ ์ œ์–ด๊ถŒ์„ ๋„˜๊ธฐ๋ ค๋ฉด ๊ฐ์ฒด๋ฅผ bean ์œผ๋กœ ๋“ฑ๋กํ•ด์•ผ ํ–ˆ๋‹ค.

์•ž์—์„œ ๋งํ–ˆ๋“ฏ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ๋นˆ์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋” ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณด์ž!


1) @Configuration + @Bean

์ด ๋ฐฉ์‹์€ ์ฃผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ œ์–ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ์„ bean์œผ๋กœ ๋“ฑ๋กํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

@Configuration
public class AppConfig {
    
    @Bean
    public ArrayList<String> array() {
    
	    return new ArrayList<String>();
    }
}

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” @Configuration ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ค€๋‹ค.

@Bean์ด ๋ถ™์€ ๋ฉ”์„œ๋“œ๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋ฐ˜ํ™˜๋œ ์ž๋ฐ” ๊ฐ์ฒด๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ๋Š” ArrayList์™€ ๊ฐ™์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ bean์œผ๋กœ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด ArrayList๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  @Bean ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด์ค˜ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด๊ฐ€ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€๋‹ค.

โ†’ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


2) @Component

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ž‘์„ฑํ•œ class๋ฅผ bean์œผ๋กœ ๋“ฑ๋ก์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

@Component๋Š” ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋ก์‹œํ‚ค๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

@Component
public class Car {

    private final Tire tire;

    @Autowired
    public Car(Tire tire) {
        this.tire = tire;
    }
}

@Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ”„๋ง์—๊ฒŒ ์ž๋™์œผ๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋ผ๊ณ  ์ง€์‹œํ•œ๋‹ค.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” Car ๋นˆ์„ ์ƒ์„ฑํ•  ๋•Œ, Tire ํƒ€์ž…์˜ ๋นˆ์„ ์ฐพ์•„์™€ ์ƒ์„ฑ์ž์— ์ฃผ์ž…ํ•œ๋‹ค.


๐Ÿšจย ๊ทธ๋Ÿผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” Car ํด๋ž˜์Šค๊ฐ€ ์–ด๋””์žˆ๋Š”์ง€ ์•Œ๊ณ  ์ฐพ์•„์™€ ๋นˆ์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ผ๊นŒ??

@ComponentScan

์ด ์–ด๋…ธํ…Œ์ด์…˜์€ @Component ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค๋“ค์„ ์ž๋™์œผ๋กœ bean ์œผ๋กœ ๋“ฑ๋กํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค

๊ทธ๋Ÿผ ์–ด๋””๋ถ€ํ„ฐ @Component ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•˜๋‚˜์š”?? โ‡’ @ComponentScan ์ด ๋ถ™์€ ํด๋ž˜์Šค์˜ ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•˜์—ฌ, @Component ๊ฐ€ ๋ถ™์€ ํด๋ž˜์Šค๋ฅผ ์ฐพ์œผ๋ฉด ๋นˆ์œผ๋กœ ๋“ฑ๋ก์‹œ์ผœ์ค€๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ๊ธฐ์กด์— ํ”„๋กœ์ ํŠธ๋ฅผ ํ• ๋•Œ @ComponentScan ์–ด๋…ธํ…Œ์ด์…˜์„ ์“ด ๊ธฐ์–ต์ด ์—†๋Š”๋ฐ์š”??

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

ํ”„๋กœ์ ํŠธ์˜ root์— Application ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ํด๋ž˜์Šค์˜ @SpringBootApplication ์–ด๋…ธํ…Œ์ด์…˜ ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	// ๊ตฌํ˜„
}

๋‚ด๋ถ€์— @ComponentScan ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœ์ ํŠธ root์— @SpringBootApplication ์ด ์žˆ๊ณ , ๊ทธ ๋‚ด๋ถ€์— @ComponentScan์ด ์žˆ์–ด ํ•ญ์ƒ ํ”„๋กœ์ ํŠธ root๋ถ€ํ„ฐ ํ•˜์œ„ ํŒจํ‚ค์ง€๊นŒ์ง€ @Component๋ฅผ ํƒ์ƒ‰ ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ์ด๋‹ค.


์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ–ˆ๋˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ดํŽด๋ณด์ž

@Controller

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 5 17 14

@Repository

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 5 17 56

@Service

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 5 18 37

@Configuration

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-09-06 แ„‹แ…ฉแ„’แ…ฎ 5 16 49

๋ชจ๋‘ ๋‚ด๋ถ€์— @Component ์–ด๋…ธํ…Œ์ด์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค๋“ค ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋Œ€์ƒ์ด ๋˜์–ด ์ž๋™ ๋นˆ ๋“ฑ๋ก์ด ๋˜์—ˆ๋˜ ๊ฒƒ์ด๋‹ค.



4๏ธโƒฃย ๋‹จ์œ„ ํ…Œ์ŠคํŠธ VS ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

1. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์ธ ํด๋ž˜์Šค๋‚˜ ๋ฉ”์„œ๋“œ์˜ ๋™์ž‘์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

์Šคํ”„๋ง์—์„œ ์ฃผ๋กœ Mockito๋‚˜ JUnit๊ณผ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ ์žฅ์ 

  • ์ž‘์€ ๋ถ€๋ถ„์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•˜๋ฏ€๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ์‹œ๊ฐ„๊ณผ ๋น„์šฉ์„ ์ ˆ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋˜๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ƒ๊ฒผ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฆฌํŒฉํ† ๋ง ์‹œ์— ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์˜ˆ๋ฅผ ํ†ตํ•ด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ๋ฒ•์„ ์•Œ์•„๋ณด์ž

// .. ์„œ๋น„์Šค ํด๋ž˜์Šค
public class CalculateService {

		public int add(int a, int b) {
				return (a + b);
		}
}
// .. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

public class CalculateServiceTest {

    private CalculateService calculateService;

    @BeforeEach
    public void setUp() {
        // ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
        calculateService = new CalculateService();
    }

    @Test
    public void testAdd() {

        // given
        int a = 5;
        int b = 3;

        // when
        int result = calculateService.add(a, b);

        // then
        assertEquals(8, result, "5 + 3 = 8");
    }
}
  • @BeforeEach
    • ๊ฐ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰๋  ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•œ๋‹ค.
    • CalculateService ์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™” ์‹œํ‚จ๋‹ค. ๋”ฐ๋ผ์„œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉด, ๊ฐ๊ฐ์˜ ํ…Œ์Šค๋Š” ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • @Test
    • JUnit์—์„œ ์ œ๊ณตํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋ฉฐ, ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ๐Ÿ“Œย ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ ์ž‘์„ฑ๋ฒ•
    • given : ํ…Œ์ŠคํŠธ์—์„œ ํ•„์š”ํ•œ ์ž…๋ ฅ๊ฐ’์„ ์ค€๋น„ํ•˜๋Š” ๋‹จ๊ณ„
    • when : ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋‹จ๊ณ„
    • then : ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋‹จ๊ณ„
  • ๐Ÿ“Œย ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” assert ๋ฉ”์„œ๋“œ
    • assertEquals(๊ธฐ๋Œ€ ๊ฐ’, ์‹ค์ œ ๊ฐ’) : ๊ธฐ๋Œ€ ๊ฐ’๊ณผ ์‹ค์ œ ๊ฐ’์ด ๊ฐ™์€์ง€ ๊ฒ€์ฆํ•œ๋‹ค.
    • assertTrue(์กฐ๊ฑด) : ์กฐ๊ฑด์ด ์ฐธ์ธ์ง€ ๊ฒ€์ฆํ•œ๋‹ค.
    • assertFalse(์กฐ๊ฑด) : ์กฐ๊ฑด์ด ๊ฑฐ์ง“์ธ์ง€ ๊ฒ€์ฆํ•œ๋‹ค.
    • assertNotNull(๊ฐ์ฒด) : ๊ฐ์ฒด๊ฐ€ null์ด ์•„๋‹Œ์ง€ ๊ฒ€์ฆํ•œ๋‹ค.

๊ทธ๋Ÿผ ์™ธ๋ถ€ ์˜์กด์„ฑ์„ ๊ฐ€์ง„ ํด๋ž˜์Šค์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ๋ ๊นŒ?

โ‡’ ์˜์กด์„ฑ์„ ๋ชจํ‚น(Mock) ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜์ž

// .. ์„œ๋น„์Šค ํด๋ž˜์Šค

public class UserService {

    private final UserRepository UserRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

		// .. UserRepository๋ฅผ ์˜์กดํ•˜๋Š” findUserById ๋ฉ”์„œ๋“œ
    public User findUserById(Long id) {
        return UserRepository.findById(id).orElseThrow(() -> new RuntimeException("ํšŒ์› ์—†์Œ"));
    }
}
// .. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

public class UserServiceTest {

    @Mock
    private UserRepository UserRepository;

    @InjectMocks
    private UserService userService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testFindUserById() {

        // given
        User mockUser = new User(1L, "seoji");
        when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));

        // when
        User user = userService.findUserById(1L);

        // then
        assertEquals("seoji", user.getName());
        verify(userRepository).findById(1L);
    }
}
  • @Mock
    • UserRepository๋ฅผ ๋ชจํ‚นํ•œ๋‹ค.
    • ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ต์‹ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  ๋ชจํ‚น๋œ repository ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • @InjectMocks
    • UserService์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ฝ”๋”ฉ๋œ UserRepository๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.
  • when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser))
    • ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋ชจํ‚น๋œ repository๊ฐ€ ์–ด๋–ค ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ง€๋ฅผ ์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
    • โ‡’ ๐Ÿ“Œย ์„œ๋น„์Šค ํด๋ž˜์Šค ์ž์ฒด์˜ ๋กœ์ง๋งŒ์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด์„œ
    • userRepository.findById(1L)์ด ํ˜ธ์ถœ๋  ๋•Œ, Optional.of(mockUser)์ด ๋ฐ˜ํ™˜๋˜๋„๋ก ํ•œ๋‹ค.
  • verify(userRepository).findById(1L)
    • ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚œ ํ›„, userRepository.findById(1L)๊ฐ€ ์‹ค์ œ๋กœ ํ˜ธ์ถœ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

2. ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ ์š”์†Œ๋‚˜ ๋ชจ๋“ˆ์ด ์‹ค์ œ๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ์ด๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ ๋ชจ๋“ˆ (์„œ๋น„์Šค, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ)์ด ํ†ตํ•ฉ๋˜์–ด ์›ํ™œํ•˜๊ฒŒ ์ƒํ˜ธ์ž‘์šฉ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.


๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋กœ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ๋ฒ•์„ ์•Œ์•„๋ณด์ž

@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @DisplayName("DisplayName : ํ…Œ์ŠคํŠธ ์ด๋ฆ„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค")
    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}
  • @SpringBootTest
    • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ ์ „์ฒด๋ฅผ ๋กœ๋“œํ•œ๋‹ค.
    • ๋ชจ๋“  ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ์— ์˜ฌ๋ฆฌ๊ณ  ์‹œ์ž‘ํ•˜๋ฏ€๋กœ ์šด์˜ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค. โ†’ ํ•˜์ง€๋งŒ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆผ
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  bean๊ณผ ์„ค์ •์ด ๋กœ๋“œ๋˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๊ณ„์ธต (Controller, Service, Repository๋“ฑ)์„ ํ†ตํ•ฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • @AutoConfigureMockMvc
    • MockMvc๋ฅผ ์ž๋™์œผ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ์Šคํ”„๋ง MVC์˜ ๋™์ž‘์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ ๊ณ„์ธต์„ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
  • MockMvc
    • HTTP ์š”์ฒญ์„ ๋ชจํ‚นํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค.
    • โ€œHTTP ์š”์ฒญ์„ ๋ชจํ‚น(Mock)ํ•œ๋‹คโ€๋Š” ๊ฒƒ์€ ์‹ค์ œ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ , ํ”„๋กœ๊ทธ๋žจ ๋‚ด๋ถ€์—์„œ ๊ฐ€์ƒ์˜ ์š”์ฒญ์„ ์ƒ์„ฑํ•˜์—ฌ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
  • mvc.perform(MockMvcRequestBuilders.get(โ€/โ€))
    • MockMvc๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP GET ์š”์ฒญ์„ โ€œ/โ€ ๊ฒฝ๋กœ๋กœ ๋ณด๋‚ธ๋‹ค.
    • ์š”์ฒญ์€ HelloController์˜ โ€œ/โ€ ๊ฒฝ๋กœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ ์ „๋‹ฌ๋œ๋‹ค.
  • andExpect(status().isOk())
    • HTTP ์‘๋‹ต ์ƒํƒœ๊ฐ€ 200 OK ์ธ์ง€ ํ™•์ธํ•œ๋‹ค
  • andExpect(content().string(equalTo("Greetings from Spring Boot!")))
    • ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.
    • ์‘๋‹ต ๋ณธ๋ฌธ ๋‚ด์šฉ์ด "Greetings from Spring Boot!"์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

๐ŸŒŸย ์‹ค์ œ ์ฝ”๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋„ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋„ ๊ฐ€๋…์„ฑ ์žˆ๊ฒŒ ์ž˜ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜์ž!

About

CEOS 20th BE Study - Spring Tutorial

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Java 100.0%