Spring/AOP

ํฌ์ธํŠธ์ปท, ์–ด๋“œ๋ฐ”์ด์Šค, ์–ด๋“œ๋ฐ”์ด์ €

an_jjin 2024. 11. 11. 21:00
๐Ÿ’ก ๊น€์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ ๊ณ ๊ธ‰ํŽธ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ํฌ์ธํŠธ์ปท, ์–ด๋“œ๋ฐ”์ด์Šค, ์–ด๋“œ๋ฐ”์ด์ €

  • ํฌ์ธํŠธ์ปท( Pointcut ): ์–ด๋””์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ• ์ง€, ์–ด๋””์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜์ง€ ์•Š์„์ง€ ํŒ๋‹จํ•˜๋Š” ํ•„ํ„ฐ๋ง ๋กœ์ง์ด๋‹ค. ์ฃผ๋กœ ํด๋ž˜์Šค์™€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์œผ๋กœ ํ•„ํ„ฐ๋ง ํ•œ๋‹ค. ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ์–ด๋–ค ํฌ์ธํŠธ(Point)์— ๊ธฐ๋Šฅ์„ ์ ์šฉํ• ์ง€ ํ•˜์ง€ ์•Š์„์ง€ ์ž˜๋ผ์„œ(cut) ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค
  • ์–ด๋“œ๋ฐ”์ด์Šค( Advice ): ์ด์ „์— ๋ณธ ๊ฒƒ ์ฒ˜๋Ÿผ ํ”„๋ก์‹œ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด๋‹ค. ๋‹จ์ˆœํ•˜๊ฒŒ ํ”„๋ก์‹œ ๋กœ์ง์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • ์–ด๋“œ๋ฐ”์ด์ €( Advisor ): ๋‹จ์ˆœํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•ด์„œ ํฌ์ธํŠธ์ปท1 + ์–ด๋“œ๋ฐ”์ด์Šค1์ด๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง์„ ์ ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ํฌ์ธํŠธ์ปท์œผ๋กœ ์–ด๋””์—? ์ ์šฉํ• ์ง€ ์„ ํƒํ•˜๊ณ , ์–ด๋“œ๋ฐ”์ด์Šค๋กœ ์–ด๋–ค ๋กœ์ง์„ ์ ์šฉํ• ์ง€ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋””์—? ์–ด๋–ค ๋กœ์ง?์„ ๋ชจ๋‘ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์–ด๋“œ๋ฐ”์ด์ €์ด๋‹ค.

์ •๋ฆฌ

์กฐ์–ธ( Advice )์„ ์–ด๋””( Pointcut )์— ํ•  ๊ฒƒ์ธ๊ฐ€?

์กฐ์–ธ์ž( Advisor )๋Š” ์–ด๋””( Pointcut )์— ์กฐ์–ธ( Advice )์„ ํ•ด์•ผํ• ์ง€ ์•Œ๊ณ  ์žˆ๋‹ค.

์—ญํ• ๊ณผ ์ฑ…์ž„

์ด๋ ‡๊ฒŒ ๊ตฌ๋ถ„ํ•œ ๊ฒƒ์€ ์—ญํ• ๊ณผ ์ฑ…์ž„์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•œ ๊ฒƒ์ด๋‹ค.

ํฌ์ธํŠธ์ปท์€ ๋Œ€์ƒ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ํ•„ํ„ฐ ์—ญํ• ๋งŒ ๋‹ด๋‹นํ•œ๋‹ค.
์–ด๋“œ๋ฐ”์ด์Šค๋Š” ๊น”๋”ํ•˜๊ฒŒ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง๋งŒ ๋‹ด๋‹นํ•œ๋‹ค.
๋‘˜์„ ํ•ฉ์น˜๋ฉด ์–ด๋“œ๋ฐ”์ด์ €๊ฐ€ ๋œ๋‹ค.

์Šคํ”„๋ง์˜ ์–ด๋“œ๋ฐ”์ด์ €๋Š” ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท + ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

์–ด๋“œ๋ฐ”์ด์ €

์–ด๋“œ๋ฐ”์ด์ €๋Š” ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ํ†ตํ•ด ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ์ œ๊ณตํ•˜๋ฉด ์–ด๋””์— ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ• ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

AdvisorTest

@Slf4j
public class AdvisorTest {

    @Test
    void advisorTest1() {
        ServiceInterface target = new ServiceImpl();
        ProxyFactory proxyFactory = new ProxyFactory(target);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(Pointcut.TRUE, new TimeAdvice());
        proxyFactory.addAdvisor(advisor);
        ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

        proxy.save();
        proxy.find();
    }
}

new DefaultPointcutAdvisor

Advisor ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ตฌํ˜„์ฒด์ด๋‹ค.

์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์–ด๋“œ๋ฐ”์ด์ €๋Š” ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋กœ ๊ตฌ์„ฑ ๋œ๋‹ค

new TimeAdvice()

์•ž์„œ ๊ฐœ๋ฐœํ•œ TimeAdvice ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

proxyFactory.addAdvisor(advisor)

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ์— ์ ์šฉํ•  ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ์ง€์ •ํ•œ๋‹ค.

์–ด๋“œ๋ฐ”์ด์ €๋Š” ๋‚ด๋ถ€์— ํฌ์ธํŠธ์ปท๊ณผ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

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

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์–ด๋“œ๋ฐ”์ด์ €๋Š” ํ•„์ˆ˜์ด๋‹ค.

์‹คํ–‰๊ฒฐ๊ณผ

ํฌ์ธํŠธ์ปท ์ง์ ‘ ๋งŒ๋“ค๊ธฐ

์ด๋ฒˆ์—๋Š” save() ๋ฉ”์„œ๋“œ์—๋Š” ์–ด๋“œ๋ฐ”์ด์Šค ๋กœ์ง์„ ์ ์šฉํ•˜์ง€๋งŒ, find() ๋ฉ”์„œ๋“œ์—๋Š” ์–ด๋“œ๋ฐ”์ด์Šค ๋กœ์ง์„ ์ ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•ด๋ณด์ž.

Pointcut ๊ด€๋ จ ์ธํ„ฐํŽ˜์ด์Šค - ์Šคํ”„๋ง ์ œ๊ณต

public interface Pointcut {
     ClassFilter getClassFilter();
     MethodMatcher getMethodMatcher();
}

public interface ClassFilter {
     boolean matches(Class<?> clazz);
}

public interface MethodMatcher {
     boolean matches(Method method, Class<?> targetClass);
     //..
}

ํฌ์ธํŠธ์ปท์€ ํฌ๊ฒŒ ClassFilter์™€ MethodMatcher ๋‘˜๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ํ•˜๋‚˜๋Š” ํด๋ž˜์Šค๊ฐ€ ๋งž๋Š”์ง€, ํ•˜๋‚˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋งž๋Š”์ง€ ํ™•์ธํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

๋‘˜๋‹ค true๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ผ๋ฐ˜์ ์œผ๋กœ ์Šคํ”„๋ง์ด ์ด๋ฏธ ๋งŒ๋“ค์–ด๋‘” ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ฐœ๋… ํ•™์Šต ์ฐจ์›์—์„œ ๊ฐ„๋‹จํžˆ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด์ž.

AdvisorTest - advisorTest2() ์ถ”๊ฐ€

@Test
@DisplayName("์ง์ ‘ ๋งŒ๋“  ํฌ์ธํŠธ์ปท")
void advisorTest2() {
    ServiceInterface target = new ServiceImpl();
    ProxyFactory proxyFactory = new ProxyFactory(target);
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(new MyPointcut(), new TimeAdvice());
    proxyFactory.addAdvisor(advisor);
    ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

    proxy.save();
    proxy.find();
}

    static class MyPointcut implements Pointcut {

        @Override
        public ClassFilter getClassFilter() {
            return ClassFilter.TRUE;
        }

        @Override
        public MethodMatcher getMethodMatcher() {
            return new MyMethodMatcher();
        }
    }

    static class MyMethodMatcher implements MethodMatcher {

        private String matchName = "save";

        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            boolean result = method.getName().equals(matchName);
            log.info("ํฌ์ธํŠธ์ปท ํ˜ธ์ถœ method={} targetClass={}", method.getName(), targetClass);
            log.info("ํฌ์ธํŠธ์ปท ๊ฒฐ๊ณผ result={}", result);
            return result;
        }

        @Override
        public boolean isRuntime() {
            return false;
        }

        @Override
        public boolean matches(Method method, Class<?> targetClass, Object... args) {
            return false;
        }
    }

์‹คํ–‰ ํ๋ฆ„ ์ •๋ฆฌ

save() ํ˜ธ์ถœ

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ”„๋ก์‹œ์˜ save()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  2. ํฌ์ธํŠธ์ปท์— Service ํด๋ž˜์Šค์˜ save() ๋ฉ”์„œ๋“œ์— ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ ์šฉํ•ด๋„ ๋ ์ง€ ๋ฌผ์–ด๋ณธ๋‹ค.
  3. ํฌ์ธํŠธ์ปท์ด true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•œ๋‹ค.
  4. ์ดํ›„ ์‹ค์ œ ์ธ์Šคํ„ด์Šค์˜ save()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

find() ํ˜ธ์ถœ

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํ”„๋ก์‹œ์˜ find()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  2. ํฌ์ธํŠธ์ปท์— Service ํด๋ž˜์Šค์˜ find() ๋ฉ”์„œ๋“œ์— ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ ์šฉํ•ด๋„ ๋ ์ง€ ๋ฌผ์–ด๋ณธ๋‹ค.
  3. ํฌ์ธํŠธ์ปท์ด false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ , ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๋„ ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
  4. ์‹ค์ œ ์ธ์Šคํ„ด์Šค๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํฌ์ธํŠธ์ปท ์‚ฌ์šฉํ•˜๊ธฐ

์Šคํ”„๋ง์€ ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ํฌ์ธํŠธ์ปท์„ ์ด๋ฏธ ๋Œ€๋ถ€๋ถ„ ์ œ๊ณตํ•œ๋‹ค.

์ด๋ฒˆ์—๋Š” ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” NameMatchMethodPointcut๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•ด๋ณด์ž.

@Test
@DisplayName("์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํฌ์ธํŠธ์ปท")
void advisorTest3() {
    ServiceInterface target = new ServiceImpl();
    ProxyFactory proxyFactory = new ProxyFactory(target);
    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    pointcut.setMappedNames("save");
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, new TimeAdvice());
    proxyFactory.addAdvisor(advisor);
    ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

    proxy.save();
    proxy.find();
}

NameMatchMethodPointcut ์‚ฌ์šฉ ์ฝ”๋“œ

 NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
 pointcut.setMappedNames("save");

NameMatchMethodPointcut์„ ์ƒ์„ฑํ•˜๊ณ  setMappedNames(...)์œผ๋กœ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ํฌ์ธํŠธ์ปท์ด ์™„์„ฑ๋œ๋‹ค.

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํฌ์ธํŠธ์ปท

AspectJExpressionPointcut: aspectJ ํ‘œํ˜„์‹์œผ๋กœ ๋งค์นญํ•œ๋‹ค.

๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ aspectJ ํ‘œํ˜„์‹์ด๊ณ  ๋‹ค๋ฅธ ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค.

์‹ค๋ฌด์—์„œ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํŽธ๋ฆฌํ•˜๊ณ  ๊ธฐ๋Šฅ๋„ ๊ฐ€์žฅ ๋งŽ์€ aspectJ ํ‘œํ˜„์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” AspectJExpressionPointcut์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ € ํ•จ๊ป˜ ์ ์šฉ

์–ด๋“œ๋ฐ”์ด์ €๋Š” ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
๋งŒ์•ฝ ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ํ•˜๋‚˜์˜ target์— ์ ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?
์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•ด์„œ ํ•˜๋‚˜์˜ target์— ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

์—ฌ๋Ÿฌ ํ”„๋ก์‹œ

MultiAdvisorTest

@Test
@DisplayName("์—ฌ๋Ÿฌ ํ”„๋ก์‹œ")
void multiAdvisorTest1() {
    //client -> proxy2(advisor2) -> proxy1(advisor1) -> target

    //ํ”„๋ก์‹œ1 ์ƒ์„ฑ
    ServiceInterface target = new ServiceImpl();
    ProxyFactory proxyFactory1 = new ProxyFactory(target);
    DefaultPointcutAdvisor advisor1 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice1());
    proxyFactory1.addAdvisor(advisor1);
    ServiceInterface proxy1 = (ServiceInterface) proxyFactory1.getProxy();

    //ํ”„๋ก์‹œ2 ์ƒ์„ฑ, target -> proxy1 ์ž…๋ ฅ
    ProxyFactory proxyFactory2 = new ProxyFactory(proxy1);
    DefaultPointcutAdvisor advisor2 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice2());
    proxyFactory2.addAdvisor(advisor2);
    ServiceInterface proxy2 = (ServiceInterface) proxyFactory2.getProxy();

    //์‹คํ–‰
    proxy2.save();
}

    @Slf4j
    static class Advice1 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            log.info("advice1 ํ˜ธ์ถœ");
            return invocation.proceed();
        }
    }

    @Slf4j
    static class Advice2 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            log.info("advice2 ํ˜ธ์ถœ");
            return invocation.proceed();
        }
    }

์ด ์ฝ”๋“œ๋Š” ๋Ÿฐํƒ€์ž„์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค.

์—ฌ๋Ÿฌ ํ”„๋ก์‹œ์˜ ๋ฌธ์ œ

์ด ๋ฐฉ๋ฒ•์ด ์ž˜๋ชป๋œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ํ”„๋ก์‹œ๋ฅผ 2๋ฒˆ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

๋งŒ์•ฝ ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ์–ด๋“œ๋ฐ”์ด์ €๊ฐ€ 10๊ฐœ ๋ผ๋ฉด 10๊ฐœ์˜ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์•ผํ•œ๋‹ค.

ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ, ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €

์Šคํ”„๋ง์€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ์— ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด๋‘์—ˆ๋‹ค.

 

@Test
@DisplayName("ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ, ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €")
void multiAdvisorTest2() {
    //client -> proxy -> advisor2 -> advisor1 -> target

    DefaultPointcutAdvisor advisor1 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice1());
    DefaultPointcutAdvisor advisor2 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice2());

    //ํ”„๋ก์‹œ1 ์ƒ์„ฑ
    ServiceInterface target = new ServiceImpl();
    ProxyFactory proxyFactory1 = new ProxyFactory(target);

    proxyFactory1.addAdvisor(advisor2);
    proxyFactory1.addAdvisor(advisor1);
    ServiceInterface proxy = (ServiceInterface) proxyFactory1.getProxy();

    //์‹คํ–‰
    proxy.save();

}

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ์— ์›ํ•˜๋Š” ๋งŒํผ addAdvisor()๋ฅผ ํ†ตํ•ด์„œ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ๋“ฑ๋กํ•˜๋ฉด ๋œ๋‹ค.
๋“ฑ๋กํ•˜๋Š” ์ˆœ์„œ๋Œ€๋กœ advisor๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” advisor2, advisor1 ์ˆœ์„œ๋กœ ๋“ฑ๋กํ–ˆ๋‹ค.

์ •๋ฆฌ

๊ฒฐ๊ณผ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๋น„๊ตํ•ด์„œ ๊ฒฐ๊ณผ๋Š” ๊ฐ™๊ณ , ์„ฑ๋Šฅ์€ ๋” ์ข‹๋‹ค.

 

์Šคํ”„๋ง์˜ AOP๋ฅผ ์ฒ˜์Œ ๊ณต๋ถ€ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜๋ฉด, AOP ์ ์šฉ ์ˆ˜ ๋งŒํผ ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๊ณ  ์ฐฉ๊ฐํ•˜๊ฒŒ ๋œ๋‹ค์Šคํ”„๋ง์€ AOP๋ฅผ ์ ์šฉํ•  ๋•Œ, ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ•ด์„œ ์ง€๊ธˆ์ฒ˜๋Ÿผ ํ”„๋ก์‹œ๋Š” ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค๊ณ , ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ์— ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ์ ์šฉํ•œ๋‹ค.

 

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

์ด๋ถ€๋ถ„์„ ๊ผญ ๊ธฐ์–ตํ•ด๋‘์ž.

์ •๋ฆฌ

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

๋‚จ์€ ๋ฌธ์ œ

ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ์™€ ์–ด๋“œ๋ฐ”์ด์ € ๊ฐ™์€ ๊ฐœ๋… ๋•๋ถ„์— ์ง€๊ธˆ๊นŒ์ง€ ๊ณ ๋ฏผํ–ˆ๋˜ ๋ฌธ์ œ๋“ค์€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

ํ”„๋ก์‹œ๋„ ๊น”๋”ํ•˜๊ฒŒ ์ ์šฉํ•˜๊ณ  ํฌ์ธํŠธ์ปท์œผ๋กœ ์–ด๋””์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ• ์ง€๋„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์›๋ณธ ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ์†๋Œ€์ง€ ์•Š๊ณ  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

๋ฌธ์ œ1 - ๋„ˆ๋ฌด ๋งŽ์€ ์„ค์ •

๋ฐ”๋กœ ProxyFactoryConfigV1, ProxyFactoryConfigV2์™€ ๊ฐ™์€ ์„ค์ • ํŒŒ์ผ์ด ์ง€๋‚˜์น˜๊ฒŒ ๋งŽ๋‹ค๋Š” ์ ์ด๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์Šคํ”„๋ง ๋นˆ์ด 100๊ฐœ๊ฐ€ ์žˆ๋‹ค๋ฉด ์—ฌ๊ธฐ์— ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ ค๋ฉด 100๊ฐœ์˜ ๋™ ์  ํ”„๋ก์‹œ ์ƒ์„ฑ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค! ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ์„ค์ • ํŒŒ์ผ ๋•Œ๋ฌธ์— ์„ค์ • ์ง€์˜ฅ์„ ๊ฒฝํ—˜ํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ์ตœ๊ทผ์—๋Š” ์Šคํ”„๋ง ๋นˆ์„ ๋“ฑ๋กํ•˜๊ธฐ ๊ท€์ฐฎ์•„์„œ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๊นŒ์ง€ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ์ง์ ‘ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ๋„ ๋ชจ์ž๋ผ์„œ, ํ”„๋ก์‹œ ๋ฅผ ์ ์šฉํ•˜๋Š” ์ฝ”๋“œ๊นŒ์ง€ ๋นˆ ์ƒ์„ฑ ์ฝ”๋“œ์— ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.

๋ฌธ์ œ2 - ์ปดํฌ๋„ŒํŠธ ์Šค์บ”

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ V3์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ง€๊ธˆ๊นŒ์ง€ ํ•™์Šตํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ํ”„๋ก์‹œ ์ ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์™œ๋ƒํ•˜๋ฉด ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์œผ๋กœ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก์„ ๋‹ค ํ•ด๋ฒ„๋ฆฐ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ํ•™์Šตํ•œ ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•˜๋ ค๋ฉด, ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ProxyFactoryConfigV1์—์„œ ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ, ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ํ”„๋ก์‹œ๋ฅผ ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋นˆ์œผ๋กœ ๋“ฑ ๋กํ•ด์•ผ ํ•œ๋‹ค.

 

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