Spring

[Spring] λ””μžμΈ νŒ¨ν„΄ : 적은 μ½”λ“œ μˆ˜μ •μœΌλ‘œ 곡톡 λ‘œμ§μ„ μž‘μ„±ν•˜κΈ°

sian han 2025. 6. 11. 16:21

πŸŽ“ 이 글은 μΈν”„λŸ°μ—μ„œ μ œκ³΅ν•˜λŠ” "μŠ€ν”„λ§ ν•΅μ‹¬ μ›λ¦¬ - κ³ κΈ‰νŽΈ" κ°•μ˜λ₯Ό μˆ˜κ°•ν•˜λ©΄μ„œ μ •λ¦¬ν•œ λ‚΄μš©μ„ λ°”νƒ•μœΌλ‘œ μž‘μ„±ν•œ κΈ€μž…λ‹ˆλ‹€.

https://inf.run/FWeFN

 

적은 μ½”λ“œ μˆ˜μ •μœΌλ‘œ 곡톡 λ‘œμ§μ„ μž‘μ„±ν•  수 있기 μœ„ν•΄ κ³ μ•ˆλœ λ©”μ„œλ“œ νŒ¨ν„΄μ„ μ†Œκ°œν•œλ‹€. 

 

곡톡 둜직 (둜그 좔적기) μš”κ΅¬μ‚¬ν•­

더보기

* λͺ¨λ“  PUBLIC λ©”μ„œλ“œμ˜ 호좜과 응닡 정보λ₯Ό 둜그둜 좜λ ₯

* μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 흐름을 λ³€κ²½ν•˜λ©΄ μ•ˆλ¨ - 둜그λ₯Ό 남긴닀고 ν•΄μ„œ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직의 λ™μž‘μ— 영ν–₯을 μ£Όλ©΄ μ•ˆλ¨

* λ©”μ„œλ“œ ν˜ΈμΆœμ— κ±Έλ¦° μ‹œκ°„

* μ •상 흐름과 μ˜ˆμ™Έ 흐름 ꡬ뢄 - μ˜ˆμ™Έ λ°œμƒ μ‹œ μ˜ˆμ™Έ 정보가 남아야 함

* λ©”μ„œλ“œ 호좜의 깊이 ν‘œν˜„

* HTTP μš”μ²­μ„ ꡬ뢄

* HTTP μš”μ²­ λ‹¨μœ„λ‘œ νŠΉμ • ID λ₯Ό λ‚¨κ²¨μ„œ μ–΄λ–€ HTTP μš”μ²­μ—μ„œ μ‹œμž‘λœ 것인지 λͺ…ν™•ν•˜κ²Œ ꡬ뢄이 κ°€λŠ₯ν•΄μ•Ό 함

* νŠΈλžœμž­μ…˜ ID (DBνŠΈλžœμž­μ…˜X)

 

β€» ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄

ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ 개인 ν”„λ‘œμ νŠΈμ— μš”μ²­λ³„ μ‹€ν–‰ μ‹œκ°„μ„ μΆ”μ ν•˜λŠ” LogTrace λ₯Ό κ°œλ°œν–ˆλ‹€. 
이해도가 μ–΄λŠμ •λ„ μžˆλ‹€κ³  μƒκ°ν•˜μ—¬ κ΄€λ ¨ν•˜μ—¬ λ”°λ‘œ 기둝해두지 μ•Šκ² λ‹€. κΈ€ μ°Έκ³ λ°”λžŒ

 

 

β€» μ „λž΅νŒ¨ν„΄

ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄ < μ „λž΅νŒ¨ν„΄μΈ 이유 : μ „λž΅νŒ¨ν„΄μ€ ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄κ³Ό λΉ„μŠ·ν•œ 역할을 ν•˜λ©΄μ„œ μƒμ†μ˜ 단점을 μ œκ±°ν•  수 μžˆλŠ” λ””μžμΈ νŒ¨ν„΄μ΄λ‹€.

  • ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄ : λΆ€λͺ¨ ν΄λž˜μŠ€μ— λ³€ν•˜μ§€ μ•ŠλŠ” 뢀뢄듀을 λͺ¨μ•„두고, λ³€ν•˜λŠ” 뢀뢄을 μžμ‹ ν΄λž˜μŠ€μ— λ‘μ–΄μ„œ 상속을 μ‚¬μš©ν•΄μ„œ 문제λ₯Ό ν•΄κ²°ν•œλ‹€.
  • μ „λž΅ νŒ¨ν„΄ : λ³€ν•˜μ§€ μ•ŠλŠ” 뢀뢄을 Context λΌλŠ” 곳에 두고, λ³€ν•˜λŠ” 뢀뢄을 Strategy λΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€κ³  ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ ν•΄μ„œ 문제λ₯Ό ν•΄κ²°ν•œλ‹€. 상속이 μ•„λ‹ˆλΌ μœ„μž„μœΌλ‘œ 문제λ₯Ό ν•΄κ²°ν•œλ‹€. κ±°λŒ€ν•œ λ¬Έλ§₯이 μ‘΄μž¬ν•˜κ³ , μ „λž΅μ΄ μ‘°κΈˆμ”© λ°”λ€ŒλŠ” 것.

 

β–Ά μ „λž΅νŒ¨ν„΄V1 의 ꡬ성

Strategy : λ³€ν•˜λŠ” 뢀뢄을 λͺ¨μ•„놓은 μΈν„°νŽ˜μ΄μŠ€

public interface Strategy {
    void call();
}
@Slf4j
public class StrategyLogic1 implements Strategy {
    @Override
    public void call() {
        log.info("λΉ„μ¦ˆλ‹ˆμŠ€ 둜직1 μ‹€ν–‰");
    }
}

 

 

ContextV1 : λ³€ν•˜μ§€ μ•ŠλŠ” λ‘œμ§μ„ κ°€μ§€κ³  μžˆλŠ” ν…œν”Œλ¦Ώ μ—­ν•  + Strategy λ₯Ό λ‚΄λΆ€ν•„λ“œλ‘œ λ‘κ³ μžˆμŒ(이걸 톡해 Strategy λ₯Ό μ£Όμž…λ°›μŒ)

public class ContextV1 {

    private Strategy strategy;

    public ContextV1(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        long startTime = System.currentTimeMillis();
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ‹€ν–‰
        strategy.call(); //μœ„μž„
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ’…λ£Œ
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}

 

 

  • Strategy ν•„λ“œμ— λ³€ν•˜λŠ” 뢀뢄인 Strategy 의 κ΅¬ν˜„μ²΄λ₯Ό μ£Όμž…ν•˜λ©΄ λœλ‹€.
  • Context μ½”λ“œλŠ” Strategy 의 κ΅¬ν˜„μ²΄λ₯Ό λ³€κ²½ν•˜κ±°λ‚˜ μƒˆλ‘œ λ§Œλ“€μ–΄λ„ Context μ½”λ“œμ—λŠ” 영ν–₯을 μ£Όμ§€ μ•ŠλŠ”λ‹€. 이처럼 μ „λž΅ νŒ¨ν„΄μ˜ 핡심은 Context λŠ” Strategy μΈν„°νŽ˜μ΄μŠ€μ—λ§Œ μ˜μ‘΄ν•œλ‹€λŠ” 점이닀. 
  • λ³€ν•˜μ§€ μ•ŠλŠ” λ‘œμ§μ„ κ°–κ³  μžˆλŠ” ν…œν”Œλ¦Ώ 역할을 ν•˜λŠ” μ½”λ“œλ₯Ό μ „λž΅νŒ¨ν„΄μ—μ„œλŠ μ»¨ν…μŠ€νŠΈλΌκ³  ν•œλ‹€. 
  • Context λŠ” 크게 λ³€ν•˜μ§€ μ•Šμ§€λ§Œ, κ·Έ λ¬Έλ§₯μ†μ—μ„œ Strategy λ₯Ό 톡해 μ „λž΅μ΄ λ³€κ²½λœλ‹€κ³  μƒκ°ν•˜λ©΄ 됨. 

 

β–Ά  μ „λž΅νŒ¨ν„΄V1 의 μ‚¬μš©

@Test
void strategyV1() {
    StrategyLogic1 strategyLogic1 = new StrategyLogic1();
    ContextV1 context1 = new ContextV1(strategyLogic1);
    context1.execute();

    StrategyLogic2 strategyLogic2 = new StrategyLogic2();
    ContextV1 context2 = new ContextV1(strategyLogic2);
    context2.execute();
}

 

Strategy 의 κ΅¬ν˜„μ²΄μΈ StrategyLogic1 의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ—¬ ContextV1에 μ£Όμž…ν•œλ‹€.

μ΄λ ‡κ²Œ ν•΄μ„œ Context μ•ˆμ— μ›ν•˜λŠ” μ „λž΅μ„ μ£Όμž…ν•œλ‹€. 

 

이 방법은 μ„  쑰립, ν›„ μ‹€ν–‰ 방법에 μ ν•©ν•˜λ‹€. Context λ‚΄λΆ€ ν•„λ“œμ— Strategy λ₯Ό 두고 μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ— λ‘˜μ„ ν•œλ²ˆ μ‘°λ¦½ν•˜κ³  λ‚˜λ©΄ κ·Έ μ΄ν›„λ‘œλŠ” Context λ₯Ό μ‹€ν–‰ν•˜κΈ°λ§Œ ν•˜λ©΄ λœλ‹€. κ·ΈλŸ¬λ‚˜ 단점은 ν•œλ²ˆ μ‘°λ¦½ν•œ 이후 μ „λž΅μ„ λ³€κ²½ν•˜κΈ°κ°€ λ²ˆκ±°λ‘­λ‹€λŠ” 점이닀. 

μ—₯ ? Setter λ₯Ό μ œκ³΅ν•΄μ„œ Strategy λ₯Ό λ„˜κ²¨ λ°›μ•„ μ œκ³΅ν•˜λ©΄ λ˜μ§€ μ•Šλ‚˜ ? ) λ§žλ‹€. κ·Έλ ‡μ§€λ§Œ Context λ₯Ό μ‹±κΈ€ν†€μœΌλ‘œ μ‚¬μš©ν•  λ•ŒλŠ” λ™μ‹œμ„± μ΄μŠˆλ“± κ³ λ €ν•  점이 λ§Žλ‹€. κ·Έλž˜μ„œ μ „λž΅μ„ μ‹€μ‹œκ°„μœΌλ‘œ λ³€κ²½ν•΄μ•Όν•˜λ©΄ μœ„μ²˜λŸΌ Context λ₯Ό ν•˜λ‚˜ 더 μƒμ„±ν•˜κ³  그곳에 λ‹€λ₯Έ Strategy λ₯Ό μ£Όμž…ν•˜λŠ” 것이 λ‚˜μ„ 수 μžˆλ‹€. 

 

μœ„ μ˜ˆμ‹œλŠ” Context 에 Strategy λΌλŠ” λ‚΄λΆ€ ν•„λ“œλ₯Ό 두고, μ£Όμž…ν•΄μ„œ μ‚¬μš©ν–ˆλ‹€. 

μ΄λ²ˆμ—λŠ” 직접 νŒŒλΌλ―Έν„°λ‘œ μ „λ‹¬ν•΄μ„œ μ‚¬μš©ν•΄λ³΄μž !

 

β–Ά μ „λž΅νŒ¨ν„΄ V2의 ꡬ성

ContextV2 : λ³€ν•˜μ§€ μ•ŠλŠ” λ‘œμ§μ„ λͺ¨μ•„λ‘λŠ” ν…œν”Œλ¦Ώ μ—­ν•  + Strategy λ₯Ό νŒŒλΌλ―Έν„°λ‘œ 전달 λ°›μŒ

@Slf4j
public class ContextV2 {

    public void execute(Strategy strategy) {
        long startTime = System.currentTimeMillis();
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ‹€ν–‰
        strategy.call(); //μœ„μž„
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ’…λ£Œ
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}
@Slf4j
public class StrategyLogic2 implements Strategy {
    @Override
    public void call() {
        log.info("λΉ„μ¦ˆλ‹ˆμŠ€ 둜직2 μ‹€ν–‰");
    }
}

 

 

β–Ά μ „λž΅νŒ¨ν„΄ V2의 μ‚¬μš©

    @Test
    void strategyV1() {
        ContextV2 context = new ContextV2();
        context.execute(new StrategyLogic1());
        context.execute(new StrategyLogic2());
    }

 

μ΄λ ‡κ²Œ ν•˜λ©΄ Context λ₯Ό μ‹€ν–‰ν•˜λŠ” μ‹œμ μ— μ›ν•˜λŠ” Strategy λ₯Ό 전달할 수 μžˆλ‹€. (V1μ—μ„œλŠ” 객체λ₯Ό μƒμ„±ν•˜λŠ” μ‹œμ μ— Strategy λ₯Ό μ£Όμž…ν•΄μ•Ό ν–ˆλ‹€. λ”°λΌμ„œ 이전 방식과 λΉ„κ΅ν•΄μ„œ 더 μœ μ—°ν•˜κ²Œ λ³€κ²½ κ°€λŠ₯ν•˜λ‹€.)

 

 

 

β€»  μ½œλ°± νŒ¨ν„΄

콜백(callback) : λ‹€λ₯Έ μ½”λ“œμ˜ μΈμˆ˜λ‘œμ„œ λ„˜κ²¨μ£ΌλŠ” μ‹€ν–‰κ°€λŠ₯ν•œ μ½”λ“œ. (ν•œλ§ˆλ””λ‘œ ν•¨μˆ˜κ°€ 인자둜 λ„˜μ–΄μ˜€λŠ” 것)

μžλ°” μ–Έμ–΄μ—μ„œ μ‹€ν–‰ κ°€λŠ₯ν•œ μ½”λ“œλ₯Ό 인수둜 λ„˜κΈ°λ €λ©΄ 객체가 ν•„μš”ν•˜λ‹€. μ΅œκ·Όμ—λŠ” 주둜 λžŒλ‹€λ₯Ό μ‚¬μš©ν•œλ‹€. 

 

ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄

  • ContextV2와 같은 λ°©μ‹μ˜ μ „λž΅νŒ¨ν„΄μ„ ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄μ΄λΌκ³  ν•œλ‹€. 
  • μŠ€ν”„λ§μ—μ„œ 이름에 XxxTemplate κ°€ μžˆλ‹€λ©΄ ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄μœΌλ‘œ λ§Œλ“€μ–΄μ Έ μžˆλ‹€ μƒκ°ν•˜λ©΄ λœλ‹€. 
    • 예: JdbcTemplate
  • Template : μ „λž΅ νŒ¨ν„΄μ˜ Context 와 κ°™λ‹€. λ³€ν•˜μ§€ μ•ŠλŠ” 뢀뢄을 λͺ¨μ•„λ‘λŠ” ν…œν”Œλ¦Ώμ΄λ‹€.
  • Callback : μ „λž΅ νŒ¨ν„΄μ˜ Strategy 와 κ°™λ‹€. λ³€ν•˜λŠ” 뢀뢄을 λͺ¨μ•„λ‘”λ‹€.

 

β–Ά ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄ V1 ꡬ성

Callback μΈν„°νŽ˜μ΄μŠ€

public interface Callback {
    void call();
}
@Slf4j
public class TimeLogTemplate {

    public void execute(Callback callback) {
        long startTime = System.currentTimeMillis();
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ‹€ν–‰
        callback.call(); //μœ„μž„
        //λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ’…λ£Œ
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}

 

 

β–Ά ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄ V1 μ‚¬μš©

void callbackV1() {
        TimeLogTemplate template = new TimeLogTemplate();
        
        template.execute(new Callback() { //읡λͺ… λ‚΄λΆ€ 클래슀
            public void call() {
                log.info("λΉ„μ¦ˆλ‹ˆμŠ€ 둜직1 μ‹€ν–‰");
            }
        });

 

  • Callback μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„μ²΄λ‘œ λ§Œλ“€λ©΄μ„œ λ™μ‹œμ— μ‹€ν–‰
  • μ½œλ°±μ„ μ‚¬μš©ν•  경우 읡λͺ… λ‚΄λΆ€ ν΄λž˜μŠ€λ‚˜ λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 νŽΈλ¦¬ν•˜λ‹€. (λ¬Όλ‘  λ³„λ„μ˜ 클래슀λ₯Ό λ§Œλ“€μ–΄μ„œ 전달해도 됨)

 


 

  • ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄ : λ‹€ν˜•μ„±κ³Ό 상속을 μ‚¬μš©ν•˜μ—¬ 문제λ₯Ό ν•΄κ²°ν•œλ‹€. λΆ€λͺ¨κ°€ λ°”λ€Œλ©΄ μžμ‹μ΄ 영ν–₯을 λ°›μŒ
  • μ „λž΅ νŒ¨ν„΄ : μœ„μž„μ„ μ‚¬μš©ν•΄ 문제λ₯Ό ν•΄κ²°ν•œλ‹€. Context 와 Strategy 둜 κ΅¬μ„±λœλ‹€. Strategy Interface λ₯Ό κ΅¬ν˜„ν•΄ μ „λž΅μ„ λ³€κ²½ν•œλ‹€. 
  • ν…œν”Œλ¦Ώ 콜백 νŒ¨ν„΄ : μ „λž΅ νŒ¨ν„΄μΈλ° Strategy λ₯Ό 인자둜 μ „λ‹¬λ°›κ²Œ ν•˜λŠ” 것과 λ™μΌν•˜λ‹€. μ΄λ•Œ μš©μ–΄λŠ” Template κ³Ό callback 이라고 μ‚¬μš©ν•œλ‹€. 읡λͺ… λ‚΄λΆ€ 클래슀 ν˜Ήμ€ λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 ꢌμž₯λœλ‹€. 

적은 μ½”λ“œλ‘œ 곡톡 λ‘œμ§μ„ μž‘μ„±ν•˜κΈ° μœ„ν•΄ κ³ μ•ˆλœ λ””μžμΈ νŒ¨ν„΄μ„ μ•Œμ•„λ΄€λ‹€. 

κ·ΈλŸ¬λ‚˜ 이 방법듀은 κ²°κ΅­ 곡톡 λ‘œμ§μ„ μ μš©ν•˜κΈ° μœ„ν•΄ 원본 μ½”λ“œλ₯Ό μˆ˜μ •ν•΄μ•Όν•œλ‹€λŠ” 단점이 μžˆλ‹€.