Spring Core Advanced

์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ณ ๊ธ‰ํŽธ ๊ฐ•์˜๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

Project

โญ๏ธ ThreadLocal

๋™์‹œ์„ฑ ๋ฌธ์ œ

  • ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ธ์Šคํ„ด์Šค ํ•„๋“œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

  • ์Šคํ”„๋ง ๋นˆ์ฒ˜๋Ÿผ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉฐ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜

ThreadLocal

  • ํŠน์ • ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ €์žฅ์†Œ

  • ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋‚ด๋ถ€ ์ €์žฅ์†Œ ์ œ๊ณต

  • ํŠน์ • ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์„ ๋ชจ๋‘ ์‚ฌ์šฉ๋ฉด ThreadLocal.remove() ํ˜ธ์ถœ๋กœ ์ €์žฅ๋œ ๊ฐ’์„ ๋ฐ˜๋“œ์‹œ ์ œ๊ฑฐ

    • ์Šค๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ(ex. WAS) ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๊ฐ’์„ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด, ์‚ฌ์šฉ์žB๊ฐ€ ์‚ฌ์šฉ์žA ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ

    • ์Šค๋ ˆ๋“œ๋Š” ์Šค๋ ˆ๋“œ ํ’€์„ ํ†ตํ•ด ์žฌ์‚ฌ์šฉ๋˜์ง€ ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์—์„œ ์ œ๊ฑฐ๋˜์ง€ ์•Š๊ณ  ๋‚จ์•„์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

commit

Template Method Pattern

๋‹คํ˜•์„ฑ(์ƒ์†๊ณผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ)์„ ํ™œ์šฉํ•ด์„œ ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„(ํ•ต์‹ฌ ๊ธฐ๋Šฅ)๊ณผ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„(๋กœ๊ทธ ์ถ”์ ๊ธฐ, ํŠธ๋žœ์žญ์…˜..)์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด

๊ตฌ์กฐ

Result

์ธ์Šคํ„ด์Šค ํ˜ธ์ถœ ๊ณผ์ •

Result
  • ๋ถ€๋ชจ ํด๋ž˜์Šค์— ํ…œํ”Œ๋ฆฟ(๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„)์„ ์ •์˜ํ•˜๊ณ , ์ผ๋ถ€ ๋ณ€๊ฒฝ๋˜๋Š” ๋กœ์ง์€ ์ž์‹ ํด๋ž˜์Šค์— ์ •์˜

  • ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์ „์ฒด ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ํŠน์ • ๋ถ€๋ถ„๋งŒ ์žฌ์ •์˜

  • ๊ฒฐ๊ตญ ์ƒ์†๊ณผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์„ ํ†ตํ•œ ๋‹คํ˜•์„ฑ์œผ๋กœ ๋ฌธ์ œ ํ•ด๊ฒฐ

  • ํด๋ž˜์Šค๋Š” ๋‹จ ํ•œ ๊ฐœ์˜ ์ฑ…์ž„์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(Single Responsibility Principle)์„ ์ž˜ ์ง€ํ‚ค๋Š” ํŒจํ„ด

  • ๋‹จ, ์ƒ์†์—์„œ ์˜ค๋Š” ๋‹จ์ ๋“ค์ด ์กด์žฌ

    • ๊ฐ•ํ•œ ์˜์กด์„ฑ์œผ๋กœ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋”๋ผ๋„ ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ์•Œ์•„์•ผ ํ•˜๊ณ 

    • ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ์ž์‹ ํด๋ž˜์Šค์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Œ

    • ์ƒ์† ๊ตฌ์กฐ๋กœ ์ธํ•ด ์ƒ์„ฑ๋˜๋Š” ํด๋ž˜์Šค๋‚˜ ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค์˜ ๋ณต์žก์„ฑ

์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค

  • ์ง€์ • ์ด๋ฆ„์ด ์—†๊ณ  ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์„ ์–ธ๋˜๋Š” ํด๋ž˜์Šค

  • ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ์ƒ์„ฑํ•  ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ์ž์‹ ํด๋ž˜์Šค ์ •์˜

AbstractTemplate template1 = new AbstractTemplate() {
    @Override
    protected void call() {
        log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1 ์‹คํ–‰");
    }
};
log.info("ํด๋ž˜์Šค ์ด๋ฆ„1={}", template1.getClass()); // class hello...TemplateMethodTest$1
template1.execute();

Template Example

public abstract class AbstractTemplate<T> {

    private final LogTrace trace;

    public AbstractTemplate(LogTrace trace) {
        this.trace = trace;
    }

    public T execute(String message) {
        TraceStatus status = null;
        try {
            status = trace.begin(message);

            //๋กœ์ง ํ˜ธ์ถœ
            T result = call();
            
            trace.end(status);
            return result;
        } catch (Exception e) {
            trace.exception(status, e);
            throw e;
        }
    }

    protected abstract T call();
}

commit

Strategy Pattern

Template Method Pattern ์˜ ์ƒ์†์œผ๋กœ ์ธํ•œ ๋‹จ์ ์„ ์œ„์ž„์œผ๋กœ ํ•ด๊ฒฐํ•œ ๋””์ž์ธ ํŒจํ„ด

๊ตฌ์กฐ

Result

์ „๋žต ํŒจํ„ด ์‹คํ–‰ ๊ณผ์ •

Result
  • ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ Context(๋ณ€ํ•˜์ง€ ์•Š๋Š” ํ…œํ”Œ๋ฆฟ)์—, ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„์„ Strategy(๋ณ€ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜) ์ธํ„ฐํŽ˜์ด์Šค์— ๋‘๊ณ , ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋ฅผ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ

    • Context์— ์›ํ•˜๋Š” Strategy ๊ตฌํ˜„์ฒด ์ฃผ์ž…

    • ํด๋ผ์ด์–ธํŠธ๋Š” Context ์‹คํ–‰

    • Context๋Š” Context ๋กœ์ง ์‹œ์ž‘

    • Context ๋กœ์ง ์ค‘๊ฐ„์— strategy.call() ํ˜ธ์ถœ๋กœ ์ฃผ์ž… ๋ฐ›์€ Strategy ๋กœ์ง ์‹คํ–‰

    • Context๋Š” ๋‚˜๋จธ์ง€ ๋กœ์ง ์‹คํ–‰

commit

์ต๋ช… ํด๋ž˜์Šค ์‚ฌ์šฉ

  • Context/Strategy ์„  ์กฐ๋ฆฝ, ํ›„ ์‹คํ–‰ ๋ฐฉ์‹์— ์ ํ•ฉ

    • ํ•„๋“œ์— Strategy ์ €์žฅ ๋ฐฉ์‹์˜ ์ „๋žต ํŒจํ„ด

  • ํ•œ ๋ฒˆ ์กฐ๋ฆฝ ์ดํ›„ Context ์‹คํ–‰๋งŒ ํ•˜๋ฉด ๋

    • ์Šคํ”„๋ง ๋กœ๋”ฉ ์‹œ์ ์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ํ†ตํ•ด ์กฐ๋ฆฝ ํ›„ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌ

  • ๋‹จ์ ์€, ์กฐ๋ฆฝ ์ดํ›„์— ์ „๋žต ๋ณ€๊ฒฝ์ด ๋ฒˆ๊ฑฐ๋กœ์›€ (์‹ฑ๊ธ€ํ†ค ์‚ฌ์šฉ ์‹œ ๋™์‹œ์„ฑ ์ด์Šˆ ๋“ฑ ๊ณ ๋ ค ์‚ฌํ•ญ์ด ์กด์žฌ)

commit

Template Callback Pattern

์ „๋žต์„ ํ•„๋“œ๋กœ ๊ฐ€์ง€์ง€ ์•Š๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ

  • ์ „๋žต ํŒจํ„ด์—์„œ ํ…œํ”Œ๋ฆฟ๊ณผ ์ฝœ๋ฐฑ ๋ถ€๋ถ„์ด ๊ฐ•์กฐ๋œ ํŒจํ„ด(GOF ํŒจํ„ด์€ ์•„๋‹ˆ๊ณ  ์Šคํ”„๋ง ๋‚ด๋ถ€์—์„œ ๋ถˆ๋ฆฌ์›€)

  • ์ฝ”๋“œ๊ฐ€ Call ์ดํ›„ ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ์ค€ ๊ณณ์˜ Back ์—์„œ ์‹คํ–‰(CallBack..)

  • ์Šคํ”„๋ง์—์„œ XxxTemplate(JdbcTemplate, RestTemplate, TransactionTemplate, RedisTemplate) ํ˜•ํƒœ๋Š” ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด์ด ์‚ฌ์šฉ๋˜์–ด ๋งŒ๋“ค์–ด์ง„ ํด๋ž˜์Šค

Result
  • ํŒŒ๋ผ๋ฏธํ„ฐ์— Strategy ์ „๋‹ฌ ๋ฐฉ์‹์˜ ์ „๋žต ํŒจํ„ด

  • ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ „๋žต์„ ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€๊ฒฝ

  • ๋‹จ์ ์€, ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ „๋žต์„ ๊ณ„์† ์ง€์ •ํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€

commit

์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค๋‚˜ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌ

๋‹จ, ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ๊ฒฝ์šฐ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์ฝœ๋ฐฑ์„ ๋ณ„๋„์˜ ํด๋ž˜์Šค๋กœ ๋งŒ๋“œ๋Š”๊ฒŒ ์ข‹์Œ

  • Context -> Template

  • Strategy -> Callback

Example

์ ์šฉ

Proxy

ํ”„๋ก์‹œ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

  • ์ ‘๊ทผ ์ œ์–ด

    • ๊ถŒํ•œ์— ๋”ฐ๋ฅธ ์ ‘๊ทผ ์ฐจ๋‹จ

    • ์บ์‹ฑ

    • ์ง€์—ฐ ๋กœ๋”ฉ

  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

    • ๊ธฐ์กด ์ œ๊ณต ๊ธฐ๋Šฅ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ˆ˜ํ–‰

    • ex. ์š”์ฒญ/์‘๋‹ต ๊ฐ’ ๋ณ€ํ˜•, ์ถ”๊ฐ€ ๋กœ๊ทธ

  • ๋‹จ์ 

    • ๋Œ€์ƒ ํด๋ž˜์Šค๋งŒ ๋‹ค๋ฅผ ๋ฟ ๋กœ์ง์€ ์œ ์‚ฌํ•˜๊ณ , ๋Œ€์ƒ ํด๋ž˜์Šค ๊ฐœ์ˆ˜๋งŒํผ ํ”„๋ก์‹œ ํด๋ž˜์Šค ์ƒ์„ฑ ํ•„์š”

    • ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์„ ํ†ตํ•ด ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ๋ชจ๋“  ๊ณณ์— ์ ์šฉ ๊ฐ€๋Šฅ

Proxy Pattern

ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•˜์—ฌ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ํŒจํ„ด

์˜๋„(intent) : ๋‹ค๋ฅธ ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌ์ž ์ œ๊ณต

Result
  • ์‹ค์ œ ๊ฐ์ฒด์™€ ํด๋ผ์ด์–ธํŠธ์˜ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ , ํ”„๋ก์‹œ ๋„์ž…์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ด

  • ์‹ค์ œ ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋˜์—ˆ๋Š”์ง€, ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋˜์—ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์Œ

ํ”„๋ก์‹œ ๊ฐ์ฒด

@Slf4j
public class CacheProxy implements Subject {

    private Subject target; // ํ”„๋ก์‹œ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์ƒ
    private String cacheValue;

    public CacheProxy(Subject target) {
        this.target = target;
    }

    /**
     * ํ”„๋ก์‹œ๋„ ์‹ค์ œ ๊ฐ์ฒด์™€ ๋ชจ์–‘์ด ๊ฐ™์•„์•ผ ํ•˜๋ฏ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„
     */
    @Override
    public String operation() {
        log.info("ํ”„๋ก์‹œ ํ˜ธ์ถœ");
        if (cacheValue == null) {
            // ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ”„๋ก์‹œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ”„๋ก์‹œ๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ์‹ค์ œ ๊ฐ์ฒด ํ˜ธ์ถœ
            cacheValue = target.operation();
        }
        return cacheValue;
    }
}

ํ”„๋ก์‹œ ๊ฐ์ฒด ์ ์šฉ

Subject realSubject = new RealSubject(); // ์‹ค์ œ ๊ฐ์ฒด
Subject cacheProxy = new CacheProxy(realSubject); // ์‹ค์ œ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์ „๋‹ฌ
ProxyPatternClient client = new ProxyPatternClient(cacheProxy); // ํ”„๋ก์‹œ ๊ฐ์ฒด ์ฃผ์ž…
client.execute(); // ์ดํ›„์—๋Š” ์บ์‹œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
client.execute(); 
client.execute();

commit

Decorator Pattern

ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ํŒจํ„ด

์˜๋„(intent) : ๊ฐ์ฒด์— ์ถ”๊ฐ€ ์ฑ…์ž„(๊ธฐ๋Šฅ)์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ธฐ๋Šฅ ํ™•์žฅ์„ ์œ„ํ•œ ์œ ์—ฐํ•œ ๋Œ€์•ˆ ์ œ๊ณต

Result
  • client -> messageDecorator(proxy) -> realComponent ๊ฐ์ฒด ์˜์กด

  • client -> timeDecorator(proxy) -> messageDecorator(proxy) -> realComponent ๊ฐ์ฒด ์˜์กด

์ ์šฉ

ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋„์ž…

  • ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก(ํ”„๋ก์‹œ ๋‚ด๋ถ€์—์„œ ์‹ค์ œ ๊ฐ์ฒด ์ฐธ์กฐ)

    • ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์ž๋ฐ” ํž™ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€๋Š” ๋ฐ˜๋ฉด

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

      • ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด์„œ ์ฐธ์กฐ๋˜๋Š” ์กด์žฌ

์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„ ํด๋ž˜์Šค(์Šคํ”„๋ง ๋นˆ ์ˆ˜๋™ ๋“ฑ๋ก)

  • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ๋„์ž…

    • ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋‹ค์ˆ˜ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š” ๋‹จ์  ์กด์žฌ

์ธํ„ฐํŽ˜์ด์Šค ์—†๋Š” ๊ตฌ์ฒด ํด๋ž˜์Šค(์Šคํ”„๋ง ๋นˆ ์ˆ˜๋™ ๋“ฑ๋ก)

  • ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ๋„์ž…

    • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๋”๋ผ๋„ ๋‹คํ˜•์„ฑ์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ํ”„๋ก์‹œ๋ฅผ ์ ์šฉ

    • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ์— ๋น„ํ•ด ์—ฌ๋Ÿฌ ๋‹จ์ ์ด ์กด์žฌ

      • ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž ํ˜ธ์ถœ ํ•„์š”

      • final ํด๋ž˜์Šค ์ƒ์† ๋ถˆ๊ฐ€

      • final ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋ถˆ๊ฐ€

์ปดํฌ๋„ŒํŠธ ์Šค์บ” ์Šคํ”„๋ง ๋นˆ ์ž๋™ ๋“ฑ๋ก

๋™์  ํ”„๋ก์‹œ

๋ฆฌํ”Œ๋ ‰์…˜

  • ํด๋ž˜์Šค/๋ฉ”์„œ๋“œ ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ๋™์ ์œผ๋กœ ํš๋“ํ•˜๊ณ , ์ฝ”๋“œ๋ฅผ ๋™์ ์œผ๋กœ ํ˜ธ์ถœ

  • ๋Ÿฐํƒ€์ž„์— ๋™์ž‘ํ•˜๋ฏ€๋กœ ์ปดํŒŒ์ผ ์‹œ์ ์— ์˜ค๋ฅ˜๋ฅผ ์žก์„ ์ˆ˜ ์—†๋Š” ๋‹จ์ 

    • ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๊ณ , ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ์ด๋‚˜ ์ผ๋ฐ˜์ ์ธ ๊ณตํ†ต ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๊ฒฝ์šฐ ๋ถ€๋ถ„์ ์œผ๋กœ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉ

@Test
void reflectionTest() throws Exception {
    Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello"); // ํด๋ž˜์Šค ๋ฉ”ํƒ€ ์ •๋ณด ํš๋“

    Hello target = new Hello();

    Method methodCallA = classHello.getMethod("callMethodA"); // ๋ฉ”์„œ๋“œ ๋ฉ”ํƒ€ ์ •๋ณด ํš๋“
    dynamicCall(methodCallA, target);

    Method methodCallB = classHello.getMethod("callMethodB");
    dynamicCall(methodCallB, target);
}

private void dynamicCall(Method method, Object target) throws Exception {
    Object result = method.invoke(target); // ํš๋“ํ•œ ๋ฉ”์„œ๋“œ ๋ฉ”ํƒ€ ์ •๋ณด๋กœ ์‹ค์ œ ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
}

JDK ๋™์  ํ”„๋ก์‹œ

๋Œ€์ƒ ํด๋ž˜์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ(์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ)

  • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ๋™์  ํ”„๋ก์‹œ ์ƒ์„ฑ(๋Ÿฐํƒ€์ž„)

    • ๊ฐ๊ฐ์˜ ๋Œ€์ƒ ๊ฐ์ฒด ํ”„๋ก์‹œ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๊ณ , ํ”„๋ก์‹œ ๋™์  ์ƒ์„ฑ(JDK ๋™์  ํ”„๋ก์‹œ) ํ›„ InvocationHandler ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด(ํ”„๋ก์‹œ ๋กœ์ง ์ •์˜) ํ•˜๋‚˜๋ฅผ ๊ณตํ†ต ์‚ฌ์šฉ

    • ๋™์  ํ”„๋ก์‹œ๋Š” ํ•ธ๋“ค๋Ÿฌ ๋กœ์ง๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ๋ฉ”์„œ๋“œ์™€ ์ธ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์‹คํ–‰

    • ๊ฐ์ฒด์˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•ด์„œ, ํด๋ž˜์Šค๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์ ์šฉํ•  ์ˆ˜ ์—†๋Š” ํ•œ๊ณ„

InvocationHandler.java

package java.lang.reflect;

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

TimeInvocationHandler.java (InvocationHandler ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด)

  • Object proxy : ํ”„๋ก์‹œ ์ž์‹ 

  • Method method : ํ˜ธ์ถœํ•œ ๋ฉ”์„œ๋“œ

  • Object[] args : ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ „๋‹ฌํ•œ ์ธ์ˆ˜

@Slf4j
public class TimeInvocationHandler implements InvocationHandler {
    private final Object target;

    public TimeInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("TimeProxy ์‹คํ–‰");
        long startTime = System.currentTimeMillis();

        Object result = method.invoke(target, args);

        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeProxy ์ข…๋ฃŒ resultTime={}", resultTime);
        return result;
    }
}

์ ์šฉ ์˜ˆ์ œ

@Test
void dynamic() {
    AInterface target = new AImpl();
    TimeInvocationHandler handler = new TimeInvocationHandler(target);

    /**
      * Proxy.newProxyInstance (๋™์  ํ”„๋ก์‹œ ์ƒ์„ฑ)
      *
      * ClassLoader loader, Class<?>[] interfaces, InvocationHandler h
      * ํด๋ž˜์Šค ๋กœ๋” ์ •๋ณด, ์ธํ„ฐํŽ˜์ด์Šค, ํ•ธ๋“ค๋Ÿฌ ๋กœ์ง
      *
      * ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์  ํ”„๋ก์‹œ ์ƒ์„ฑ ๋ฐ ํ•ธ๋“ค๋Ÿฌ ๋กœ์ง์˜ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
      */
    AInterface proxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]{AInterface.class}, handler);

    proxy.call();
    log.info("targetClass={}", target.getClass()); // targetClass=class hello.proxy.jdkdynamic.code.AImpl
    log.info("proxyClass={}", proxy.getClass()); // proxyClass=class com.sun.proxy.$Proxy12
}

์‹คํ–‰ ์ˆœ์„œ

  1. JDK ๋™์  ํ”„๋ก์‹œ์˜ call() ์‹คํ–‰ proxy.call();

  2. JDK ๋™์  ํ”„๋ก์‹œ๋Š” InvocationHandler.invoke() ํ˜ธ์ถœ

  3. TimeInvocationHandler ๋‚ด๋ถ€ ๋กœ์ง ์ˆ˜ํ–‰ ๋ฐ method.invoke(target, args) ํ˜ธ์ถœ.

  4. target์˜ ์‹ค์ œ ๊ฐ์ฒด AImpl ์ธ์Šคํ„ด์Šค์˜ call() ์‹คํ–‰

  5. AImpl ์ธ์Šคํ„ด์Šค์˜ call() ์‹คํ–‰์ด ๋๋‚˜๋ฉด TimeInvocationHandler ์‘๋‹ต

example

์ ์šฉ

Result

CGLIB

๋Œ€์ƒ ํด๋ž˜์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์„ ๊ฒฝ์šฐ(๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ)

  • ์ธํ„ฐํŽ˜์ด์Šค ์—†์ด ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜(์ƒ์†) ๋™์  ํ”„๋ก์‹œ ์ƒ์„ฑ

    • ์ƒ์† ์‚ฌ์šฉ์œผ๋กœ ์ธํ•œ ์ œ์•ฝ

      • ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์š”

      • final ํด๋ž˜์Šค๋Š” ์ƒ์† ๋ถˆ๊ฐ€

      • final ๋ฉ”์„œ๋“œ๋Š” ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋ถˆ๊ฐ€

  • JDK ๋™์  ํ”„๋ก์‹œ ์‹คํ–‰ ๋กœ์ง์— InvocationHandler๋ฅผ ์ œ๊ณตํ•˜๋“ฏ, MethodInterceptor ์ œ๊ณต

MethodInterceptor.java

package org.springframework.cglib.proxy;

/**
 * obj : CGLIB ์ ์šฉ ๊ฐ์ฒด
 * method : ํ˜ธ์ถœ๋œ ๋ฉ”์„œ๋“œ
 * args : ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์— ์ „๋‹ฌ๋œ ์ธ์ˆ˜
 * proxy : ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์— ์‚ฌ์šฉ
 */
public interface MethodInterceptor extends Callback {
    Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    Object result = proxy.invoke(target, args); // ์‹ค์ œ ๋Œ€์ƒ ๋™์  ํ˜ธ์ถœ(CGLIB๋Š” ์„ฑ๋Šฅ์ƒ Method ๋Œ€์‹  MethodProxy ์‚ฌ์šฉ)
    return result;
}

CGLIB ์˜ˆ์ œ

Spring Proxy Factory

ํ”„๋ก์‹œ ์ƒ์„ฑ์€ ProxyFactory ๋กœ์ง์€ Advice

๋‚จ์€ ๋ฌธ์ œ์ .. -> ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

  • ๋„ˆ๋ฌด ๋งŽ์€ ์„ค์ •์ด ํ•„์š”

    • ์Šคํ”„๋ง ๋นˆ์ด 100๊ฐœ ์žˆ๋‹ค๋ฉด, ํ”„๋ก์‹œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ ์šฉ์„ ์œ„ํ•ด 100๊ฐœ์˜ ๋™์  ํ”„๋ก์‹œ ์ƒ์„ฑ ํ•„์š”

  • ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Proxy Factory ์ ์šฉ ๋ถˆ๊ฐ€๋Šฅ

    • ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ ์ƒํƒœ์ด๋ฏ€๋กœ

ใ…‡ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ JDK ๋™์  ํ”„๋ก์‹œ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” CGLIB ์ ์šฉ

  • ๋™์  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ฉํ•ด์„œ ๋งŒ๋“ค์–ด์ฃผ๋Š” ProxyFactory ์ œ๊ณต

  • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด JDK ๋™์  ํ”„๋ก์‹œ ์‚ฌ์šฉ, ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ์žˆ๋‹ค๋ฉด CGLIB ์‚ฌ์šฉ(default)

Result

ใ…‡ JDK ๋™์  ํ”„๋ก์‹œ, CGLIB ๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ ์šฉ

  • InvocationHandler,MethodInterceptor ๋ฅผ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ , Advice ๋งŒ ์ƒ์„ฑ

  • org.aopalliance.intercept.MethodInterceptor ๊ตฌํ˜„์œผ๋กœ Advice ์ƒ์„ฑ

Result

ใ…‡ ํŠน์ • ์กฐ๊ฑด์— ํ”„๋ก์‹œ ๋กœ์ง์„ ์ ์šฉํ•˜๋Š” ๊ณตํ†ต ๊ธฐ๋Šฅ

  • Pointcut ๊ฐœ๋… ๋„์ž…์œผ๋กœ ์ผ๊ด€์„ฑ์žˆ๊ฒŒ ํ•ด๊ฒฐ

/** new ProxyFactory(target)
  * ํ”„๋ก์‹œ ํ˜ธ์ถœ ๋Œ€์ƒ์„ ํ•จ๊ป˜ ์ „๋‹ฌ
  * target ์ธ์Šคํ„ด์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด, JDK ๋™์  ํ”„๋ก์‹œ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ
  * ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๊ณ  ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ์žˆ๋‹ค๋ฉด, CGLIB๋ฅผ ํ†ตํ•ด์„œ ๋™์  ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑ
  */
ProxyFactory proxyFactory = new ProxyFactory(target);

/** setProxyTargetClass(true)
 * ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์–ด๋„ CGLIB ์‚ฌ์šฉ ๋ฐ ํƒ€๊ฒŸ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ(CGLIB) ์‚ฌ์šฉ
 */
proxyFactory.setProxyTargetClass(true);

/** .addAdvice(new TimeAdvice())
  * ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด์„œ ๋งŒ๋“  ํ”„๋ก์‹œ๊ฐ€ ์‚ฌ์šฉํ•  ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง์„ ์„ค์ •
  * JDK ๋™์  ํ”„๋ก์‹œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” InvocationHandler ์™€ CGLIB๊ฐ€ ์ œ๊ณตํ•˜๋Š” MethodInterceptor ์˜ ๊ฐœ๋…๊ณผ ์œ ์‚ฌ
  */
proxyFactory.addAdvice(new TimeAdvice());

/** proxyFactory.getProxy()
  *  ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
  */
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

MethodInterceptor ๊ตฌํ˜„์œผ๋กœ Advice ์ƒ์„ฑ ์˜ˆ์ œ

Spring Proxy Factory ์‚ฌ์šฉ ์˜ˆ์ œ

Pointcut, Advice, Advisor

ํ•ต์‹ฌ. ํ•˜๋‚˜์˜ Target ์— ์—ฌ๋Ÿฌ AOP๊ฐ€ ๋™์‹œ์— ์ ์šฉ๋˜์–ด๋„, ์Šคํ”„๋ง์˜ AOP๋Š” Target ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ๋งŒ ์ƒ์„ฑ

Result

Pointcut : ๋Œ€์ƒ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ํ•„ํ„ฐ ์—ญํ• 

  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์–ด๋А ๊ณณ์— ์ ์šฉ/๋ฏธ์ ์šฉํ• ์ง€ ํŒ๋‹จํ•˜๋Š” ํ•„ํ„ฐ๋ง ๋กœ์ง

  • ์ฃผ๋กœ ํด๋ž˜์Šค์™€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์œผ๋กœ ํ•„ํ„ฐ๋ง

  • ์Šคํ”„๋ง ์ œ๊ณต Pointcut

    • ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ Pointcut

      • AspectJExpressionPointcut : aspectJ ํ‘œํ˜„์‹ ๋งค์นญ (์‹ค๋ฌด์—์„œ ์ฃผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ)

      • NameMatchMethodPointcut : ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ๋งค์นญํ•œ๋‹ค

      • JdkRegexpMethodPointcut : JDK ์ •๊ทœ ํ‘œํ˜„์‹ ๊ธฐ๋ฐ˜ ๋งค์นญ

      • TruePointcut : ํ•ญ์ƒ ์ฐธ ๋ฐ˜ํ™˜

      • AnnotationMatchingPointcut : ์• ๋…ธํ…Œ์ด์…˜ ๋งค์นญ

  • Pointcut ์˜ ๋‘ ๊ฐ€์ง€ ์—ญํ•  โ€ผ๏ธ

    • ์ƒ์„ฑ ๋‹จ๊ณ„ -> ํ”„๋ก์‹œ ์ ์šฉ ์—ฌ๋ถ€ ํŒ๋‹จ (ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ์กฐ๊ฑด ๋ชจ๋‘ ๋น„๊ต)

    • ์‚ฌ์šฉ ๋‹จ๊ณ„ -> advice(๋ถ€๊ฐ€ ๊ธฐ๋Šฅ) ์ ์šฉ ์—ฌ๋ถ€ ํŒ๋‹จ

Advice : ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง ๋‹ด๋‹น

  • ํ”„๋ก์‹œ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ(=ํ”„๋ก์‹œ ๋กœ์ง)

Advisor : ํ•˜๋‚˜์˜ Pointcut, ํ•˜๋‚˜์˜ Advice๋ฅผ ๊ฐ–๋Š” ๊ฒƒ

ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(Pointcut.TRUE, new TimeAdvice()); // Advisor ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ตฌํ˜„์ฒด

proxyFactory.addAdvisor(advisor);
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

โญ๏ธ BeanPostProcessor

๋นˆ ์ €์žฅ์†Œ์— ๊ฐ์ฒด๋ฅผ ๋“ฑ๋กํ•˜๊ธฐ ์ง์ „ ์กฐ์ž‘์„ ํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ(BeanPostProcessor)๋ฅผ ์‚ฌ์šฉ(๋นˆ ์ƒ์„ฑ ํ›„ ์ฒ˜๋ฆฌ ์šฉ๋„)

  • Spring Proxy Factory ์˜ ๋‹จ์ (๋งŽ์€ ์„ค์ •, ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ ๊ฐ์ฒด ์ ์šฉ์˜ ์–ด๋ ค์›€)์„ ํ•ด๊ฒฐ

Result
  1. ์ƒ์„ฑ: ์Šคํ”„๋ง ๋นˆ ๋Œ€์ƒ ๊ฐ์ฒด ์ƒ์„ฑ(@Bean, @ComponentScan..)

  2. ์ „๋‹ฌ: ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ๋นˆ ์ €์žฅ์†Œ์— ๋“ฑ๋กํ•˜๊ธฐ ์ง์ „์— ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ์— ์ „๋‹ฌ

  3. ํ›„ ์ฒ˜๋ฆฌ ์ž‘์—…: ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋Š” ์ „๋‹ฌ๋œ ์Šคํ”„๋ง ๋นˆ ๊ฐ์ฒด๋ฅผ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ๋ฐ”๋€Œ์น˜๊ธฐ ๊ฐ€๋Šฅ

  4. ๋“ฑ๋ก: ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋Š” ๋นˆ ๋ฐ˜ํ™˜. ์ „๋‹ฌ ๋œ ๋นˆ์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ•ด๋‹น ๋นˆ์ด ๋“ฑ๋ก๋˜๊ณ , ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ๋นˆ ์ €์žฅ์†Œ์— ๋“ฑ๋ก

BeanPostProcessor interface

  • ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด BeanPostProcessor ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ํ›„ ์Šคํ”„๋ง ๋นˆ ๋“ฑ๋ก

  • postProcessBeforeInitialization : ๊ฐ์ฒด ์ƒ์„ฑ ์ดํ›„ @PostConstruct ๊ฐ™์€ ์ดˆ๊ธฐํ™” ๋ฐœ์ƒ ์ „ ํ˜ธ์ถœ๋˜๋Š” ํฌ์ŠคํŠธ ํ”„๋กœ์„ธ์„œ

  • postProcessAfterInitialization : ๊ฐ์ฒด ์ƒ์„ฑ ์ดํ›„ @PostConstruct ๊ฐ™์€ ์ดˆ๊ธฐํ™” ๋ฐœ์ƒ ํ›„ ํ˜ธ์ถœ๋˜๋Š” ํฌ์ŠคํŠธ ํ”„๋กœ์„ธ์„œ

public interface BeanPostProcessor {
  Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException
 Object postProcessAfterInitialization(Object bean, String beanName) throws
BeansException
}

์ ์šฉ

  • BeanPostProcessor ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ํ”„๋ก์‹œ๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก ๊ฐ€๋Šฅ

    • ์ˆ˜๋™ ๋“ฑ๋ก ๋นˆ์„ ํฌํ•จํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ๊นŒ์ง€ ๋ชจ๋‘ ํ”„๋ก์‹œ ์ ์šฉ์ด ๊ฐ€๋Šฅ

    • ์„ค์ • ํŒŒ์ผ์—์„œ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋ถˆํ•„์š”

Result

๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ ์ ์šฉ

์Šคํ”„๋ง ์ œ๊ณต ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ

์Šคํ”„๋ง AOP ๋Š” Pointcut ์„ ์‚ฌ์šฉํ•ด์„œ ํ”„๋ก์‹œ ์ ์šฉ ๋Œ€์ƒ ์—ฌ๋ถ€ ์ฒดํฌ

  • ํ”„๋ก์‹œ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์—๋งŒ ํ”„๋ก์‹œ ์ ์šฉ

  • ํ”„๋ก์‹œ ๋‚ด๋ถ€ ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ ๋˜์—ˆ์„ ๋•Œ ์–ด๋“œ๋ฐ”์ด์Šค ์ ์šฉ

์˜์กด์„ฑ ์ถ”๊ฐ€๋ก

implementation 'org.springframework.boot:spring-boot-starter-aop'
  • aspectjweaver: aspectJ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ AOP ๊ด€๋ จ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋นˆ์— ๋“ฑ๋ก

    • AnnotationAwareAspectJAutoProxyCreator ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์Šคํ”„๋ง ๋นˆ์— ์ž๋™์œผ๋กœ ๋“ฑ๋ก

AutoProxyCreator

Result
  • ์ž๋™์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ

  • ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ Advisor ๋“ค์„ ์ž๋™์œผ๋กœ ์ฐพ์•„์„œ ํ”„๋ก์‹œ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์— ์ž๋™์œผ๋กœ ํ”„๋ก์‹œ ์ ์šฉ

  • ํ”„๋ก์‹œ๋ฅผ ๋ชจ๋“  ๊ณณ์— ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋น„์šฉ ๋‚ญ๋น„์ด๋ฏ€๋กœ ํฌ์ธํŠธ์ปท์œผ๋กœ ํ•„ํ„ฐ๋ง ํ›„ ํ•„์š”ํ•œ ๊ณณ์— ์ตœ์†Œํ•œ์˜ ํ”„๋ก์‹œ ์ ์šฉ

  • Advisor1, Advisor2, 3, 4.. ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํฌ์ธํŠธ์ปท์˜ ์กฐ๊ฑด์„ ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋”๋ผ๋„ ํ”„๋ก์‹œ๋ฅผ ํ•œ ๊ฐœ๋งŒ ์ƒ์„ฑํ•˜๊ณ  ํ”„๋ก์‹œ๋Š” ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜๋Š” ์—ฌ๋Ÿฌ Advisor๋ฅผ ์†Œ์œ 

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ ์ ์šฉ

AspectJExpressionPointcut

  • AOP์— ํŠนํ™”๋œ ์ •๋ฐ€ํ•œ ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹(AspectJ) ์ ์šฉ

/** package ๊ธฐ์ค€ ํฌ์ธํŠธ์ปท ์ ์šฉ
  * AspectJExpressionPointcut : AspectJ ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹ ์ ์šฉ
  * execution(* hello.proxy.app..*(..)) : AspectJ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹
  *      * : ๋ชจ๋“  ๋ฐ˜ํ™˜ ํƒ€์ž…
  *      hello.proxy.app.. : ํ•ด๋‹น ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ํŒจํ‚ค์ง€
  *      *(..) : * ๋ชจ๋“  ๋ฉ”์„œ๋“œ ์ด๋ฆ„, (..) ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ƒ๊ด€ ์—†์Œ
  * -> hello.proxy.app ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋Š” ํฌ์ธํŠธ์ปท์˜ ๋งค์นญ ๋Œ€์ƒ
  */
@Bean
public Advisor advisor2(LogTrace logTrace) {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("execution(* hello.proxy.app..*(..))");
    LogTraceAdvice advice = new LogTraceAdvice(logTrace);
    //advisor = pointcut + advice
    return new DefaultPointcutAdvisor(pointcut, advice);
}

/** method ๊ธฐ์ค€ ํฌ์ธํŠธ์ปท ์ ์šฉ
  * hello.proxy.app ํŒจํ‚ค์ง€์™€ ํ•˜์œ„ ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋Š” ํฌ์ธํŠธ์ปท์˜ ๋งค์นญํ•˜๋˜,
  * noLog() ๋ฉ”์„œ๋“œ๋Š” ์ œ์™ธ
  */
@Bean
public Advisor advisor3(LogTrace logTrace) {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))");
    LogTraceAdvice advice = new LogTraceAdvice(logTrace);
    //advisor = pointcut + advice
    return new DefaultPointcutAdvisor(pointcut, advice);
}
  • ์Šคํ”„๋ง์— ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด Advisor(pointcut, advice ๋กœ ๊ตฌ์„ฑ)๋ฅผ ๋งŒ๋“ค์–ด์„œ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ๊ฐ€ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ

  • ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ๋Š” ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ Advisor ๋“ค์„ ์ฐพ๊ณ , ์Šคํ”„๋ง ๋นˆ๋“ค์— ์ž๋™์œผ๋กœ ํฌ์ธํŠธ์ปท์ด ๋งค์นญ๋˜๋Š” ๊ฒฝ์šฐ ํ”„๋ก์‹œ๋ฅผ ์ ์šฉ

@Aspect ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ pointcut ๊ณผ advice ๋ฅผ ๋งŒ๋“ค๊ณ  ํ”„๋ก์‹œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

โญ๏ธ @Aspect Proxy

  • @Aspect ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ pointcut ๊ณผ advice ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š” Advisor ์˜ ํŽธ๋ฆฌํ•œ ์ƒ์„ฑ ์ง€์›

  • ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ(AnnotationAwareAspectJAutoProxyCreator)๋ฅผ ํ†ตํ•ด @Aspect ๋ฅผ ์ฐพ์•„์„œ Advisor ๋กœ ๋ณ€ํ™˜/์ €์žฅ, Advisor ๊ธฐ๋ฐ˜์œผ๋กœ ํ•„์š”ํ•œ ๊ณณ์— ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑ

Result

@Aspect -> Advisor ๋ณ€ํ™˜ ๊ณผ์ •

  1. ์‹คํ–‰: ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ ํ˜ธ์ถœ

  2. ๋ชจ๋“  @Aspect ๋นˆ ์กฐํšŒ: ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—์„œ @Aspect ์ด ๋ถ™์€ ์Šคํ”„๋ง ๋นˆ์„ ๋ชจ๋‘ ์กฐํšŒ

  3. ์–ด๋“œ๋ฐ”์ด์ € ์ƒ์„ฑ: @Aspect ์–ด๋“œ๋ฐ”์ด์ € ๋นŒ๋”(BeanFactoryAspectJAdvisorsBuilder)๋ฅผ ํ†ตํ•ด @Aspect ์• ๋…ธํ…Œ์ด์…˜ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์–ด๋“œ๋ฐ”์ด์ € ์ƒ์„ฑ

  4. @Aspect ๊ธฐ๋ฐ˜ ์–ด๋“œ๋ฐ”์ด์ € ์ €์žฅ: ์ƒ์„ฑํ•œ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ @Aspect ์–ด๋“œ๋ฐ”์ด์ € ๋นŒ๋” ๋‚ด๋ถ€์— ์ €์žฅ

@Aspect ์–ด๋“œ๋ฐ”์ด์ € ๋นŒ๋”(BeanFactoryAspectJAdvisorsBuilder)

  • @Aspect ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํฌ์ธํŠธ์ปท, ์–ด๋“œ๋ฐ”์ด์Šค, ์–ด๋“œ๋ฐ”์ด์ € ์ƒ์„ฑ ๋ฐ ๋ณด๊ด€(์บ์‹ฑ)

Result
  • ์ž๋™ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑ๊ธฐ์˜ ๋™์ž‘๊ณผ ๋™์ผํ•œ๋ฐ, @Aspect Advisor ์กฐํšŒ ๋ถ€๋ถ„์ด ์ถ”๊ฐ€

Aspect ์ ์šฉ ํด๋ž˜์Šค

@Slf4j
@Aspect // ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ์ ์šฉ ์‹œ ํ•„์š”
public class LogTraceAspect {

    private final LogTrace logTrace;

    public LogTraceAspect(LogTrace logTrace) {
        this.logTrace = logTrace;
    }

    /**
     * Pointcut + Advice = Advisor
     *
     * Pointcut : @Around ๊ฐ’์— ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹ ์‚ฝ์ž… (ํ‘œํ˜„์‹์€ AspectJ ํ‘œํ˜„์‹ ์‚ฌ์šฉ)
     * Advice : @Around ๋ฉ”์„œ๋“œ = Advice
     * ProceedingJoinPoint : ์‹ค์ œ ํ˜ธ์ถœ ๋Œ€์ƒ, ์ „๋‹ฌ ์ธ์ž, ์–ด๋–ค ๊ฐ์ฒด์™€ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ์ •๋ณด ํฌํ•จ(MethodInvocation invocation ๊ณผ ์œ ์‚ฌ)
     */
    @Around("execution(* hello.proxy.app..*(..))") //=> Pointcut path
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { //=> Advice Logic

        TraceStatus status = null;

        // log.info("target={}", joinPoint.getTarget()); //์‹ค์ œ ํ˜ธ์ถœ ๋Œ€์ƒ
        // log.info("getArgs={}", joinPoint.getArgs()); //์ „๋‹ฌ์ธ์ž
        // log.info("getSignature={}", joinPoint.getSignature()); //join point์‹œ๊ทธ๋‹ˆ์ฒ˜

        try {
            String message = joinPoint.getSignature().toShortString();
            status = logTrace.begin(message);

            // ์‹ค์ œ ํ˜ธ์ถœ ๋Œ€์ƒ(target) ํ˜ธ์ถœ
            Object result = joinPoint.proceed();

            logTrace.end(status);
            return result;
        } catch (Exception e) {
            logTrace.exception(status, e);
            throw e;
        }
    }
}

@Aspect ํ”„๋ก์‹œ - ์ ์šฉ

โญ๏ธ Spring AOP

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์€ ํฌ๊ฒŒ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Œ

์—ฌ๊ธฐ์„œ, ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ ์šฉ์˜ ๋ฌธ์ œ

  • ์ ์šฉ ์‹œ ๋งŽ์€ ๋ฐ˜๋ณต ํ•„์š”

  • ์—ฌ๋Ÿฌ ๊ณณ์— ์ค‘๋ณต ์ฝ”๋“œ ๋ฐœ์ƒ

  • ๋ณ€๊ฒฝ ์‹œ ์ค‘๋ณต์œผ๋กœ ๋งŽ์€ ์ˆ˜์ • ํ•„์š”

  • ์ ์šฉ ๋Œ€์ƒ ๋ณ€๊ฒฝ ์‹œ ๋งŽ์€ ์ˆ˜์ • ํ•„์š”

Aspect

  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์–ด๋””์— ์ ์šฉํ• ์ง€ ์„ ํƒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋‚˜๋กœ ํ•ฉํ•˜์—ฌ ๋งŒ๋“ค์–ด์ง„ ๋ชจ๋“ˆ

    • Advisor(Pointcut + Advice) ๋„ ๊ฐœ๋…์ƒ ํ•˜๋‚˜์˜ Aspect

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐ”๋ผ๋ณด๋Š” ๊ด€์ ์„ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์—์„œ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ(cross-cutting concerns) ๊ด€์ ์œผ๋กœ ๋ณด๋Š” ๊ฒƒ

  • Aspect ๋ฅผ ์‚ฌ์šฉํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์„ ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ AOP(Aspect-Oriented Programming)

  • OOP ๋ฅผ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹Œ ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์šด OOP์˜ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„ ๋ณด์กฐ ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ

AspectJ Framework

  • ์Šคํ”„๋ง AOP๋Š” ๋Œ€๋ถ€๋ถ„ AspectJ ๋ฌธ๋ฒ•์„ ์ฐจ์šฉํ•˜๊ณ , ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ์ ์šฉ(AspectJ ์ œ๊ณต ๊ธฐ๋Šฅ ์ผ๋ถ€๋งŒ ์ œ๊ณต)

  • AspectJ Framework๋Š” ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ์˜ ๊น”๋”ํ•œ ๋ชจ๋“ˆํ™”

    • ์ž๋ฐ” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ๊ด€์  ์ง€ํ–ฅ ํ™•์žฅ

    • ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ์˜ ๊น”๋”ํ•œ ๋ชจ๋“ˆํ™”

    • ์˜ค๋ฅ˜ ๊ฒ€์‚ฌ ๋ฐ ์ฒ˜๋ฆฌ

    • ๋™๊ธฐํ™”

    • ์„ฑ๋Šฅ ์ตœ์ ํ™”(์บ์‹ฑ)

    • ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ๋กœ๊น…

AOP ์ ์šฉ ๋ฐฉ์‹

์ปดํŒŒ์ผ ์‹œ์ 

Result
  • .java ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผ๋Ÿฌ(AspectJ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํŠน๋ณ„ํ•œ ์ปดํŒŒ์ผ๋Ÿฌ)๋ฅผ ์‚ฌ์šฉํ•ด์„œ .class ๋ฅผ ๋งŒ๋“œ๋Š” ์‹œ์ ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง ์ถ”๊ฐ€ (=Weaving / aspect ์™€ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์—ฐ๊ฒฐ)

  • ๋‹จ์ , ์ปดํŒŒ์ผ ์‹œ์ ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ ค๋ฉด ํŠน๋ณ„ํ•œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ  ๋ณต์žก

ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ 

Result
  • ์ž๋ฐ”๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ž๋ฐ”๋Š” .class ํŒŒ์ผ์„ JVM ๋‚ด๋ถ€์˜ ํด๋ž˜์Šค ๋กœ๋”์— ๋ณด๊ด€. ์ด๋•Œ ์ค‘๊ฐ„์—์„œ .class ํŒŒ์ผ์„ ์กฐ์ž‘ํ•œ ๋‹ค์Œ JVM์— ๋กœ๋“œ

    • ๋Œ€๋ถ€๋ถ„ ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด๋“ค์ด java Instrumentation ๋ฐฉ์‹ ์‚ฌ์šฉ

  • ๋‹จ์ , ๋กœ๋“œ ํƒ€์ž„ ์œ„๋น™์€ ์ž๋ฐ”๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ํŠน๋ณ„ํ•œ ์˜ต์…˜(java -javaagent)์„ ํ†ตํ•ด ํด๋ž˜์Šค ๋กœ๋” ์กฐ์ž‘๊ธฐ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์ด ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์šด์˜์ด ์–ด๋ ค์›€

๋Ÿฐํƒ€์ž„ ์‹œ์ (ํ”„๋ก์‹œ)

Result
  • ๋Ÿฐํƒ€์ž„ ์‹œ์ (์ปดํŒŒ์ผ์ด ๋๋‚˜๊ณ , ํด๋ž˜์Šค ๋กœ๋”์— ํด๋ž˜์Šค๋„ ๋‹ค ์˜ฌ๋ผ๊ฐ€๊ณ , ์ด๋ฏธ ์ž๋ฐ”๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋‚œ ๋‹ค์Œ ์ƒํƒœ, ์ž๋ฐ”์˜ main ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ดํ›„) ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ์Šคํ”„๋ง ๋นˆ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉ(AOP)

  • ๋‹จ์ , ํ”„๋ก์‹œ ์‚ฌ์šฉ์œผ๋กœ AOP ๊ธฐ๋Šฅ์— ์ผ๋ถ€ ์ œ์•ฝ(final, ์ƒ์†, ์ƒ์„ฑ์ž, ..)์ด ์žˆ์ง€๋งŒ, ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์—์„œ ๋ณต์žกํ•œ ์„ค์ • ๋‹จ๊ณ„๊ฐ€ ๋ถˆํ•„์š”

๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ์ ์šฉ๋˜๋Š” ์ฐจ์ด

  • ์ปดํŒŒ์ผ ์‹œ์ : ์‹ค์ œ ๋Œ€์ƒ ์ฝ”๋“œ์— ์• ์ŠคํŒฉํŠธ๋ฅผ ํ†ตํ•œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ํ˜ธ์ถœ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ (AspectJ ์ง์ ‘ ์‚ฌ์šฉ ํ•„์š”)

  • ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ : ์‹ค์ œ ๋Œ€์ƒ ์ฝ”๋“œ์— ์• ์ŠคํŒฉํŠธ๋ฅผ ํ†ตํ•œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ํ˜ธ์ถœ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ (AspectJ ์ง์ ‘ ์‚ฌ์šฉ ํ•„์š”)

  • ๋Ÿฐํƒ€์ž„ ์‹œ์ : ์‹ค์ œ ๋Œ€์ƒ ์ฝ”๋“œ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋Š” ๋Œ€์‹  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ์ ์šฉ (ํ•ญ์ƒ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์‚ฌ์šฉ -> ์Šคํ”„๋ง AOP ์‚ฌ์šฉ ๋ฐฉ์‹)

Join Point(AOP๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ง€์ )

  • AOP๋Š” ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์œ„์น˜ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋‹ค์–‘ํ•œ ์œ„์น˜์— ์ ์šฉ ๊ฐ€๋Šฅ

    • ์ ์šฉ ๊ฐ€๋Šฅ ์ง€์ : ์ƒ์„ฑ์ž, ํ•„๋“œ ๊ฐ’ ์ ‘๊ทผ, static ๋ฉ”์„œ๋“œ ์ ‘๊ทผ, ๋ฉ”์„œ๋“œ ์‹คํ–‰

  • ์ปดํŒŒ์ผ ์‹œ์  / ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ 

    • ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ์กฐ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ๋ชจ๋“  ์ง€์ ์— ๋‹ค ์ ์šฉ ๊ฐ€๋Šฅ

  • ์Šคํ”„๋ง AOP

    • ํ”„๋ก์‹œ ๋ฐฉ์‹์„ ์‚ฌ์šฉ(์˜ค๋ฒ„๋ผ์ด๋”ฉ ๊ฐœ๋…์œผ๋กœ ๋™์ž‘)ํ•˜๋ฏ€๋กœ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ง€์ ์—๋งŒ AOP ์ ์šฉ ๊ฐ€๋Šฅ

    • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํ”„๋ง ๋นˆ์—๋งŒ AOP ์ ์šฉ ๊ฐ€๋Šฅ

  • AspectJ๋Š” ๋” ์„ฌ์„ธํ•˜๊ณ  ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, ์•Œ์•„์•ผ ํ•  ๋‚ด์šฉ์ด ๋งŽ๊ณ , ์ž๋ฐ” ๊ด€๋ จ ๋ณต์žกํ•œ ์„ค์ •์ด ๋งŽ์œผ๋ฏ€๋กœ, ์‹ค๋ฌด์—์„œ๋Š” ๋ณ„๋„ ์„ค์ • ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํ”„๋ง ์ œ๊ณต AOP ๊ธฐ๋Šฅ๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ

AOP ์šฉ์–ด

Join point

  • AOP๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ง€์ (์œ„์น˜, ๋ฉ”์†Œ๋“œ ์‹คํ–‰, ์ƒ์„ฑ์ž ํ˜ธ์ถœ, ํ•„๋“œ ๊ฐ’ ์ ‘๊ทผ, static ๋ฉ”์„œ๋“œ ์ ‘๊ทผ)

  • ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šคํ”„๋ง AOP๋Š” ํ•ญ์ƒ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ง€์ ์œผ๋กœ ์ œํ•œ

Pointcut

  • Pointcut ์ค‘์—์„œ Advice๊ฐ€ ์ ์šฉ๋  ์œ„์น˜ ์„ ๋ณ„(์ฃผ๋กœ AspectJ ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ด์„œ ์ง€์ •)

  • ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šคํ”„๋ง AOP๋Š” ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ง€์ ๋งŒ Pointcut์œผ๋กœ ์„ ๋ณ„ ๊ฐ€๋Šฅ

Target

  • Advice(๋ถ€๊ฐ€ ๊ธฐ๋Šฅ)๋ฅผ ๋ฐ›๋Š” ๊ฐ์ฒด, Pointcut์œผ๋กœ ๊ฒฐ์ •

Advice

  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ

  • Around, Before, After ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ Advic ์กด์žฌ

Aspect

  • Advice + Pointcut์„ ๋ชจ๋“ˆํ™” ํ•œ ๊ฒƒ(@Aspect)

  • ์—ฌ๋Ÿฌ Advice์™€ Pointcut ํ•จ๊ป˜ ์กด์žฌ ๊ฐ€๋Šฅ

Advisor

  • ํ•˜๋‚˜์˜ Advice์™€ ํ•˜๋‚˜์˜ Pointcut์œผ๋กœ ๊ตฌ์„ฑ

  • ์Šคํ”„๋ง AOP์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ํŠน๋ณ„ํ•œ ์šฉ์–ด

Weaving

  • Pointcut์œผ๋กœ ๊ฒฐ์ •ํ•œ ํƒ€์ผ“์˜ Join point์— Advice๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ

  • ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

  • AOP ์ ์šฉ์„ ์œ„ํ•ด ์• ์ŠคํŽ™ํŠธ๋ฅผ ๊ฐ์ฒด์— ์—ฐ๊ฒฐํ•œ ์ƒํƒœ

    • ์ปดํŒŒ์ผ ํƒ€์ž„(AspectJ compiler)

    • ๋กœ๋“œ ํƒ€์ž„

    • ๋Ÿฐํƒ€์ž„, ์Šคํ”„๋ง AOP๋Š” ๋Ÿฐํƒ€์ž„, ํ”„๋ก์‹œ ๋ฐฉ์‹

AOP Proxy

  • AOP ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ํ”„๋ก์‹œ ๊ฐ์ฒด

  • ์Šคํ”„๋ง์—์„œ AOP ํ”„๋ก์‹œ๋Š” JDK ๋™์  ํ”„๋ก์‹œ ๋˜๋Š” CGLIB ํ”„๋ก์‹œ

โญ๏ธ AOP ๊ตฌํ˜„

implementation 'org.springframework.boot:spring-boot-starter-aop'
  • AOP ๊ธฐ๋Šฅ ์‚ฌ์šฉ์„ ์œ„ํ•ด spring-boot-starter-aop dependency ์ถ”๊ฐ€

  • @Aspect ์‚ฌ์šฉ์„ ์œ„ํ•ด @EnableAspectJAutoProxy ์„ค์ •์ด ํ•„์š”ํ•˜์ง€๋งŒ, ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€

@Aspect ํด๋ž˜์Šค๋ฅผ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•

  • @Bean ์„ ์‚ฌ์šฉํ•ด์„œ ์ง์ ‘ ๋“ฑ๋ก

  • @Component ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•ด์„œ ์ž๋™ ๋“ฑ๋ก

  • @Import ์ฃผ๋กœ ์„ค์ • ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ(@Configuration)

์Šคํ”„๋ง AOP ๊ตฌํ˜„ ๊ธฐ๋ณธ

@Pointcut

  • ํฌ์ธํŠธ์ปท ์‹œ๊ทธ๋‹ˆ์ฒ˜: ๋ฉ”์„œ๋“œ ์ด๋ฆ„ + ํŒŒ๋ผ๋ฏธํ„ฐ

  • ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์€ void

@Aspect
@Component
public class Aspect {

    /**
     * @Around ์• ๋…ธํ…Œ์ด์…˜์˜ ๊ฐ’์€ Pointcut
     * @Around ์• ๋…ธํ…Œ์ด์…˜์˜ ๋ฉ”์„œ๋“œ๋Š” Advice
     * execution(* hello.aop.order..*(..)) -> hello.aop.order ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ํŒจํ‚ค์ง€( .. )๋ฅผ ์ง€์ •ํ•˜๋Š” AspectJ ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹
     */
    @Around("execution(* hello.aop.order..*(..))")
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("[log] {}", joinPoint.getSignature()); // join point ์‹œ๊ทธ๋‹ˆ์ฒ˜
        return joinPoint.proceed();
    }

    //------------------------------------------------------

    /** pointcut signature
     *  pointcut expression : hello.aop.order ํŒจํ‚ค์ง€์™€ ํ•˜์œ„ ํŒจํ‚ค์ง€
     */
    @Pointcut("execution(* hello.aop.order..*(..))")
    private void allOrder() {
    }

    @Around("allOrder()")
    public Object doLog2(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("[log] {}", joinPoint.getSignature());
        return joinPoint.proceed();
    }

    //------------------------------------------------------

    // ํด๋ž˜์Šค ์ด๋ฆ„ ํŒจํ„ด์ด *Service
    @Pointcut("execution(* *..*Service.*(..))")
    private void allService() {
    }

    /**
     * hello.aop.order ํŒจํ‚ค์ง€์™€ ํ•˜์œ„ ํŒจํ‚ค์ง€ ์ด๋ฉด์„œ,
     * ํด๋ž˜์Šค ์ด๋ฆ„ ํŒจํ„ด์ด *Service
     */
    @Around("allOrder() && allService()")
    public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {

        try {
            log.info("[ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘] {}", joinPoint.getSignature());
            Object result = joinPoint.proceed();
            log.info("[ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹] {}", joinPoint.getSignature());
            return result;
        } catch (Exception e) {
            log.info("[ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ] {}", joinPoint.getSignature());
            throw e;
        } finally {
            log.info("[๋ฆฌ์†Œ์Šค ๋ฆด๋ฆฌ์ฆˆ] {}", joinPoint.getSignature());
        }
    }
}

Advice ์ˆœ์„œ

  • ์–ด๋“œ๋ฐ”์ด์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š์Œ

  • @Order ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์–ด๋“œ๋ฐ”์ด์Šค ๋‹จ์œ„๊ฐ€ ์•„๋‹ˆ๋ผ ํด๋ž˜์Šค ๋‹จ์œ„๋กœ ์ ์šฉ ํ•„์š”

Advice ์ข…๋ฅ˜

์ฐธ๊ณ .

  • JoinPoint Interface ์ฃผ์š” ๊ธฐ๋Šฅ

    • getArgs() : ๋ฉ”์„œ๋“œ ์ธ์ˆ˜ ๋ฐ˜ํ™˜

    • getThis() : ํ”„๋ก์‹œ ๊ฐ์ฒด ๋ฐ˜ํ™˜

    • getTarget() : ๋Œ€์ƒ ๊ฐ์ฒด ๋ฐ˜ํ™˜

    • getSignature() : ์กฐ์–ธ๋˜๋Š” ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์„ค๋ช… ๋ฐ˜ํ™˜

    • toString() : ์กฐ์–ธ๋˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์œ ์šฉํ•œ ์„ค๋ช… ๋ฐ˜ํ™˜

  • ProceedingJoinPoint Interface ์ฃผ์š” ๊ธฐ๋Šฅ

    • proceed() : ๋‹ค์Œ ์–ด๋“œ๋ฐ”์ด์Šค๋‚˜ ํƒ€์ผ“ ํ˜ธ์ถœ

Result
  • @Around : ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „/ํ›„์— ์ˆ˜ํ–‰

    • ๋‹ค๋ฅธ ์–ด๋“œ๋ฐ”์ด์Šค ๊ธฐ๋Šฅ ๋ชจ๋‘ ์ฒ˜๋ฆฌ(์กฐ์ธ ํฌ์ธํŠธ ์‹คํ–‰ ์—ฌ๋ถ€ ์„ ํƒ, ๋ฐ˜ํ™˜ ๊ฐ’ ๋ณ€ํ™˜, ์˜ˆ์™ธ ๋ณ€ํ™˜ ๋“ฑ)

    • ๋‹ค์Œ ์–ด๋“œ๋ฐ”์ด์Šค๋‚˜ ํƒ€์ผ“ ํ˜ธ์ถœ์„ ์œ„ํ•ด ProceedingJoinPoint ์‚ฌ์šฉํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์–ด๋“œ๋ฐ”์ด์Šค๋Š” JoinPoint ์‚ฌ์šฉ

    • ํ•ญ์ƒ joinPoint.proceed() ํ˜ธ์ถœ ํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์„ ์ฃผ์˜

  • @Before : ์กฐ์ธ ํฌ์ธํŠธ ์‹คํ–‰ ์ „์— ์‹คํ–‰

    • ์ž‘์—… ํ๋ฆ„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€

    • ๋ฉ”์„œ๋“œ ์ข…๋ฃŒ ์‹œ ๋‹ค์Œ ํƒ€์ผ“(proceed()) ์ž๋™ ํ˜ธ์ถœ

  • @After : ์กฐ์ธ ํฌ์ธํŠธ๊ฐ€ ์ •์ƒ ๋˜๋Š” ์˜ˆ์™ธ์— ๊ด€๊ณ„์—†์ด ์‹คํ–‰

    • ๋ฉ”์„œ๋“œ ์‹คํ–‰์ด ์ข…๋ฃŒ๋˜๋ฉด ์‹คํ–‰(=finally)

    • ์ •์ƒ ๋ฐ ์˜ˆ์™ธ ๋ฐ˜ํ™˜ ์กฐ๊ฑด์„ ๋ชจ๋‘ ์ฒ˜๋ฆฌ

    • ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค ํ•ด์ œ์— ์‚ฌ์šฉ

  • @AfterReturning : ์กฐ์ธ ํฌ์ธํŠธ ์ •์ƒ ์™„๋ฃŒ ํ›„ ์‹คํ–‰

    • returning ์†์„ฑ ์ด๋ฆ„์€ ์–ด๋“œ๋ฐ”์ด์Šค ๋ฉ”์„œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„ ์ผ์น˜

    • returning ์ ˆ์— ์ง€์ •๋œ ํƒ€์ž…์˜ ๊ฐ’(Obejct)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋งŒ ๋Œ€์ƒ

    • ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ์ฒด ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€

  • @AfterThrowing : ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ๊ฒฝ์šฐ ์‹คํ–‰

    • @AfterReturning ํŠน์ง•๊ณผ ๋™์ผ

@Before("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint) {
    log.info("[before] {}", joinPoint.getSignature());
}

@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
    log.info("[return] {} return={}", joinPoint.getSignature(), result);
}

@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
    log.info("[ex] {} message={}", joinPoint.getSignature(), ex.getMessage());
}

@After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint) {
    log.info("[after] {}", joinPoint.getSignature());
}
  • @Around ๊ฐ€ ๊ฐ€์žฅ ๋„“์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ, @Before, @After ์™€ ๊ฐ™์ด ์ œ์•ฝ์ด ์žˆ๋Š” ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ช…ํ™•ํ•˜๊ฒŒ ์„ค๊ณ„๋ฅผ ํ•ด๋ณด์ž.

์–ด๋“œ๋ฐ”์ด์Šค ์ข…๋ฅ˜

ํฌ์ธํŠธ์ปท

Pointcut ์ง€์‹œ์ž

  • ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹(AspectJ pointcut expression)์€ execution ๊ฐ™์€ ํฌ์ธํŠธ์ปท ์ง€์‹œ์ž(PCD, Pointcut Designator)๋กœ ์‹œ์ž‘

  • ํฌ์ธํŠธ์ปท ์ง€์‹œ์ž ์ข…๋ฅ˜

    • execution : ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์กฐ์ธ ํฌ์ธํŠธ ๋งค์นญ(๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ , ๊ธฐ๋Šฅ๋„ ๋ณต์žก)

    • within : ํŠน์ • ํƒ€์ž… ๋‚ด์˜ ์กฐ์ธ ํฌ์ธํŠธ ๋งค์นญ

    • args : ์ธ์ž๊ฐ€ ์ฃผ์–ด์ง„ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค์ธ ์กฐ์ธ ํฌ์ธํŠธ

    • this : ์Šคํ”„๋ง ๋นˆ ๊ฐ์ฒด(์Šคํ”„๋ง AOP ํ”„๋ก์‹œ)๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์กฐ์ธ ํฌ์ธํŠธ

    • target : Target ๊ฐ์ฒด(์Šคํ”„๋ง AOP ํ”„๋ก์‹œ๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ์‹ค์ œ ๋Œ€์ƒ)๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์กฐ์ธ ํฌ์ธํŠธ

    • @target : ์‹คํ–‰ ๊ฐ์ฒด์˜ ํด๋ž˜์Šค์— ์ฃผ์–ด์ง„ ํƒ€์ž…์˜ ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ์กฐ์ธ ํฌ์ธํŠธ

    • @within : ์ฃผ์–ด์ง„ ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ํƒ€์ž… ๋‚ด ์กฐ์ธ ํฌ์ธํŠธ

    • @annotation : ๋ฉ”์„œ๋“œ๊ฐ€ ์ฃผ์–ด์ง„ ์• ๋…ธํ…Œ์ด์…˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์กฐ์ธ ํฌ์ธํŠธ๋ฅผ ๋งค์นญ

    • @args : ์ „๋‹ฌ๋œ ์‹ค์ œ ์ธ์ˆ˜์˜ ๋Ÿฐํƒ€์ž„ ํƒ€์ž…์ด ์ฃผ์–ด์ง„ ํƒ€์ž…์˜ ์• ๋…ธํ…Œ์ด์…˜์„ ๊ฐ–๋Š” ์กฐ์ธ ํฌ์ธํŠธ

    • bean : ์Šคํ”„๋ง ์ „์šฉ ํฌ์ธํŠธ์ปท ์ง€์‹œ์ž, ๋นˆ ์ด๋ฆ„์œผ๋กœ ํฌ์ธํŠธ์ปท ์ง€์ •

execution ๋ฌธ๋ฒ•

  • execution(modifiers-pattern? ret-type-pattern declaring-type-pattern namepattern(param-pattern) throws-pattern?)

    • execution(์ ‘๊ทผ์ œ์–ด์žํŒจํ„ด? ๋ฐ˜ํ™˜ํƒ€์ž…ํŒจํ„ด ์„ ์–ธํƒ€์ž…ํŒจํ„ด? ๋ฉ”์„œ๋“œ์ด๋ฆ„ํŒจํ„ด(ํŒŒ๋ผ๋ฏธํ„ฐ) ์˜ˆ์™ธํŒจํ„ด?)

      • ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์กฐ์ธ ํฌ์ธํŠธ ๋งค์นญ

      • ?๋Š” ์ƒ๋žต ๊ฐ€๋Šฅํ•œ ํŒจํ„ด

      • * ํŒจํ„ด ์ง€์ • ๊ฐ€๋Šฅ

ํŒจํ‚ค์ง€ ํŒจ์นญ ๊ทœ์น™

  • hello.aop.member.(1).(2)

    • (1): ํƒ€์ž…

    • (2): ๋ฉ”์„œ๋“œ ์ด๋ฆ„

  • . : ์ •ํ™•ํ•˜๊ฒŒ ํ•ด๋‹น ์œ„์น˜์˜ ํŒจํ‚ค์ง€

  • .. : ํ•ด๋‹น ์œ„์น˜์˜ ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ํŒจํ‚ค์ง€๋„ ํฌํ•จ

๋ฉ”์„œ๋“œ/ํŒจํ‚ค์ง€ ์ด๋ฆ„ ๋งค์นญ

ํŒŒ๋ผ๋ฏธํ„ฐ ๋งค์นญ ๊ทœ์น™

  • (String) : ์ •ํ™•ํ•˜๊ฒŒ String ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ

  • () : ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์Œ

  • (*) : ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ, ๋‹จ ๋ชจ๋“  ํƒ€์ž… ํ—ˆ์šฉ

  • (*, *) : ์ •ํ™•ํžˆ ๋‘ ๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ, ๋‹จ ๋ชจ๋“  ํƒ€์ž… ํ—ˆ์šฉ

  • (..) : ์ˆซ์ž์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋ชจ๋“  ํŒŒ๋ผ๋ฏธํ„ฐ, ๋ชจ๋“  ํƒ€์ž… ํ—ˆ์šฉ. ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์–ด๋„ ํ—ˆ์šฉ (= 0..*)

  • (String, ..) : String ํƒ€์ž…์œผ๋กœ ์‹œ์ž‘. ์ˆซ์ž์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋ชจ๋“  ํŒŒ๋ผ๋ฏธํ„ฐ, ๋ชจ๋“  ํƒ€์ž… ํ—ˆ์šฉ

    • ex. (String) , (String, Xxx) , (String, Xxx, Xxx) ํ—ˆ์šฉ

ํƒ€์ž…/ํŒŒ๋ผ๋ฏธํ„ฐ ๋งค์นญ

within ์ง€์‹œ์ž

  • ํŠน์ • ํƒ€์ž… ๋‚ด ์กฐ์ธ ํฌ์ธํŠธ์— ๋Œ€ํ•œ ๋งค์นญ ์ œํ•œ

    • ํ•ด๋‹น ํƒ€์ž…์ด ๋งค์นญ๋˜๋ฉด ๊ทธ ์•ˆ์˜ ๋ฉ”์„œ๋“œ(์กฐ์ธ ํฌ์ธํŠธ)๋“ค์ด ์ž๋™์œผ๋กœ ๋งค์นญ

    • execution ํƒ€์ž… ๋ถ€๋ถ„๋งŒ ์‚ฌ์šฉ

    • ๋ถ€๋ชจ ํƒ€์ž… ์ง€์ • ๋ถˆ๊ฐ€

    • ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ๋ณดํ†ต execution ์‚ฌ์šฉ

within ์ง€์‹œ์ž

args ์ง€์‹œ์ž

  • ์ธ์ž๊ฐ€ ์ฃผ์–ด์ง„ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค์ธ ์กฐ์ธ ํฌ์ธํŠธ๋กœ ๋งค์นญ

  • executionr vs args

    • executionr

      • ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์˜ ์ •ํ™•ํ•œ ๋งค์นญ

      • ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ์ •๋ณด(๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜) ๊ธฐ๋ฐ˜ ํŒ๋‹จ / ์ •์ 

    • args

      • ๋ถ€๋ชจ ํƒ€์ž… ํ—ˆ์šฉ

      • ์‹ค์ œ ๋„˜์–ด์˜จ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค(๋Ÿฐํƒ€์ž„์— ์ „๋‹ฌ๋œ ์ธ์ˆ˜) ๊ธฐ๋ฐ˜ ํŒ๋‹จ / ๋™์ 

      • ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ ๋ณด๋‹ค ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์— ์ฃผ๋กœ ์‚ฌ์šฉ

args

@target, @within ์ง€์‹œ์ž

ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์— ํ•จ๊ป˜ ์‚ฌ์šฉ

  • @target : ์ธ์Šคํ„ด์Šค ๊ธฐ์ค€์œผ๋กœ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์˜ ์กฐ์ธ ํฌ์ธํŠธ๋ฅผ ์„ ์ •

    • ๋ถ€๋ชจ ํƒ€์ž…์˜ ๋ฉ”์„œ๋“œ๋„ ์ ์šฉ

  • @within : ์„ ํƒ๋œ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋งŒ ์กฐ์ธ ํฌ์ธํŠธ๋กœ ์„ ์ •

    • ๋ถ€๋ชจ ํƒ€์ž…์˜ ๋ฉ”์„œ๋“œ๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Œ

@target, @within

์ฐธ๊ณ . args, @args, @target ์ง€์‹œ์ž๋Š” ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ !!!

  • ์‹ค์ œ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ, ์‹คํ–‰๋  ๋•Œ ์–ด๋“œ๋ฐ”์ด์Šค ์ ์šฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ”„๋ก์‹œ๊ฐ€ ์žˆ์–ด์•ผ๋งŒ(์‹คํ–‰ ์‹œ์ ) ํŒ๋‹จ ๊ฐ€๋Šฅ

  • ๋‹จ, ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์‹œ์ ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์ด๋ฏ€๋กœ args, @args, @target ์ง€์‹œ์ž๋Š” ์Šคํ”„๋ง์˜ ๋ชจ๋“  ๋นˆ์— AOP๋ฅผ ์ ์šฉํ•˜๋ ค๊ณ  ์‹œ๋„ -> ์Šคํ”„๋ง ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ ์ค‘์—๋Š” final ์ง€์ • ๋นˆ๋“ค๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜ ๋ฐœ์ƒ

  • ์ตœ๋Œ€ํ•œ ํ”„๋ก์‹œ ์ ์šฉ ๋Œ€์ƒ์„ ์ถ•์†Œํ•˜๋Š” ํ‘œํ˜„์‹(execution)๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ

@annotation, @args ์ง€์‹œ์ž

  • @annotation : ์ฃผ์–ด์ง„ ์• ๋…ธํ…Œ์ด์…˜(@MethodAop)์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์กฐ์ธ ํฌ์ธํŠธ ๋งค์นญ

  • @args : ๋Ÿฐํƒ€์ž„ ํƒ€์ž…์— ์ „๋‹ฌ๋œ ์ธ์ˆ˜๊ฐ€ ์ฃผ์–ด์ง„ ํƒ€์ž…์˜(@Check) ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ๊ฒฝ์šฐ์— ๋งค์นญ

@annotation, @args

bean ์ง€์‹œ์ž

  • ๋นˆ ์ด๋ฆ„์œผ๋กœ AOP ์ ์šฉ ์—ฌ๋ถ€ ์ง€์ •(์Šคํ”„๋ง ์ „์šฉ ํฌ์ธํŠธ์ปท ์ง€์‹œ์ž)

bean

this, target ์ง€์‹œ์ž

  • this : ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํฌ์ธํŠธ์ปท ๋งค์นญ

  • target : ์Šคํ”„๋ง AOP ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” ์‹ค์ œ target ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํฌ์ธํŠธ์ปท ๋งค์นญ

    • ํ”„๋ก์‹œ ๋Œ€์ƒ์ธ this ๋Š” ๊ตฌ์ฒด ํด๋ž˜์Šค ์ง€์ • ์‹œ ํ”„๋ก์‹œ ์ƒ์„ฑ ์ „๋žต์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Œ

        • ์™€ ๊ฐ™์€ ํŒจํ„ด ์‚ฌ์šฉ ๋ถˆ๊ฐ€

      • ๋ถ€๋ชจ ํƒ€์ž… ํ—ˆ์šฉ

    • ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ ๋ณด๋‹ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์— ์ฃผ๋กœ ์‚ฌ์šฉ

this vs target

๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌ

  • ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•ด์„œ ์–ด๋“œ๋ฐ”์ด์Šค์— ๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌ ๊ฐ€๋Šฅ

    • this, target, args,@target, @within, @annotation, @args

    • ๋ฉ”์„œ๋“œ์— ์ง€์ •ํ•œ ํƒ€์ž…์œผ๋กœ ์ œํ•œ

๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌ

โญ๏ธ AOP ์‹ค์ „์˜ˆ์ œ

์ฐธ๊ณ . ์Šคํ”„๋ง์˜ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ AOP๋Š” @Transactional

โญ๏ธ ์ฃผ์˜์‚ฌํ•ญ

ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ํ•œ๊ณ„ - ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœ

  • ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์‹œ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋˜๋ฏ€๋กœ ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ, ๋Œ€์ƒ ๊ฐ์ฒด์˜ ๋‚ด๋ถ€์—์„œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ(์ž์‹ ์˜ ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ)์ด ๋ฐœ์ƒํ•˜๋ฉด ํ”„๋ก์‹œ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ

  • ์Šคํ”„๋ง์€ ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ ํ˜ธ์ถœ์— ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์—†์Œ

Result
Result

ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ํ•œ๊ณ„ - ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP์˜ ๋‚ด๋ถ€ ํ˜ธ์ถœ ๋ฌธ์ œ

ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ํ•œ๊ณ„. ๋Œ€์•ˆ I. ์ž๊ธฐ ์ž์‹  ์ฃผ์ž…

  • ์ž์‹ ์˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด์„œ ํ˜ธ์ถœ

๋Œ€์•ˆ I. ์ž๊ธฐ ์ž์‹  ์ฃผ์ž…

ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ํ•œ๊ณ„. ๋Œ€์•ˆ II. ์ง€์—ฐ ์กฐํšŒ

  • ObjectProvider(Provider), ApplicationContext ์‚ฌ์šฉ

    • ObjectProvider : ๊ฐ์ฒด ์กฐํšŒ๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ ์‹œ์ ์—์„œ ์‹ค์ œ ๊ฐ์ฒด ์‚ฌ์šฉ ์‹œ์ (.getObject())์œผ๋กœ ์ง€์—ฐ

๋Œ€์•ˆ II. ์ง€์—ฐ ์กฐํšŒ

ํ”„๋ก์‹œ ๋ฐฉ์‹์˜ AOP ํ•œ๊ณ„. ๋Œ€์•ˆ III. ๊ตฌ์กฐ ๋ณ€๊ฒฝ

  • ๋‚ด๋ถ€ ํ˜ธ์ถœ์„ ๋ณ„๋„ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌ

Result

๋Œ€์•ˆ III. ๊ตฌ์กฐ ๋ณ€๊ฒฝ

ํ”„๋ก์‹œ ๊ธฐ์ˆ ์˜ ํ•œ๊ณ„

ํƒ€์ž… ์บ์ŠคํŒ…

ํ”„๋ก์‹œ ์บ์ŠคํŒ… ๋ฌธ์ œ๋Š” ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ์‹œ ๋ฐœ์ƒ

  • JDK ๋™์  ํ”„๋ก์‹œ : ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ์ƒ์„ฑ

    • ํ”„๋ก์‹œ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์บ์ŠคํŒ… ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๊ตฌ์ฒด ํด๋ž˜์Šค๋กœ ํƒ€์ž… ์บ์ŠคํŒ…์ด ๋ถˆ๊ฐ€๋Šฅ(์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํ”„๋ก์‹œ์ด๋ฏ€๋กœ..)

  • CGLIB : ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ ์ƒ์„ฑ

    • ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋˜๋ฏ€๋กœ, ๊ตฌ์ฒด ํด๋ž˜์Šค๋กœ ํƒ€์ž… ์บ์ŠคํŒ… ๊ฐ€๋Šฅ

ํ”„๋ก์‹œ ๊ธฐ์ˆ ์˜ ํ•œ๊ณ„ - ํƒ€์ž… ์บ์ŠคํŒ…

์˜์กด๊ด€๊ณ„ ์ฃผ์ž…

JDK ๋™์  ํ”„๋ก์‹œ

  • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋Œ€์ƒ ๊ฐ์ฒด Impl ํƒ€์ž…์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๋ถˆ๊ฐ€

Result

CGLIB

  • ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋Œ€์ƒ ๊ฐ์ฒด Impl ํƒ€์ž…์— ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… ๊ฐ€๋Šฅ

Result
@Autowired MemberService memberService; // ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… : JDK ๋™์  ํ”„๋ก์‹œ O, CGLIB O
@Autowire MemberServiceImpl memberServiceImpl; // ์˜์กด๊ด€๊ณ„ ์ฃผ์ž… : JDK ๋™์  ํ”„๋ก์‹œ X, CGLIB O

ํ”„๋ก์‹œ ๊ธฐ์ˆ ๊ณผ ํ•œ๊ณ„ - ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…

CGLIB ํ”„๋ก์‹œ ๋ฌธ์ œ์ 

  • ๋Œ€์ƒ ํด๋ž˜์Šค์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜

  • ์ƒ์„ฑ์ž๋ฅผ 2๋ฒˆ ํ˜ธ์ถœ

    • ์‹ค์ œ target ๊ฐ์ฒด ์ƒ์„ฑ

    • ํ”„๋ก์‹œ ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ๋ถ€๋ชจ ํด๋ž˜์Šค ์ƒ์„ฑ์ž ํ˜ธ์ถœ

  • final ํ‚ค์›Œ๋“œ ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

์Šคํ”„๋ง์˜ ํ”„๋ก์‹œ ๊ธฐ์ˆ ์˜ ํ•œ๊ณ„ ํ•ด๊ฒฐ์ฑ…

  • ์Šคํ”„๋ง 3.2 : CGLIB๋ฅผ ์Šคํ”„๋ง ๋‚ด๋ถ€์— ํ•จ๊ป˜ ํŒจํ‚ค์ง•

  • ์Šคํ”„๋ง 4.0 : objenesis ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜ ๋ฌธ์ œ, ์ƒ์„ฑ์ž 2๋ฒˆ ํ˜ธ์ถœ ๋ฌธ์ œ ํ•ด๊ฒฐ

  • ์Šคํ”„๋ง ๋ถ€ํŠธ 2.0 : CGLIB ๊ธฐ๋ณธ ์‚ฌ์šฉ

Last updated