[Spring] Spring Advisor์ Pointcut - ์ค์ ํธ
์ด์ ๊ธ์์ DefaultPointcutAdvisor์ ๋ค์ํ Pointcut๋ค์ ๋ํ ๊ฐ๋ ์ ๋ค๋ค๋ดค์ต๋๋ค.
2022.10.10 - [Programming/Spring] - [Spring] Spring Advisor์ Pointcut - ๊ฐ๋ ํธ
[Spring] Spring Advisor์ Pointcut - ๊ฐ๋ ํธ
Spring AOP ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด Advice๋ฅผ ๋ง๋ค์ด ๋ฉ์๋์ ์ ํ์ฒ๋ฆฌ๋ฅผ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด ๊ตฌํํด๋ดค์ต๋๋ค. 2022.05.16 - [Programming/Spring] - [Spring] Spring Advice๋ก ์ปค์คํ ์ด๋๋ฐ์ด์ค ๋ง๋ค๊ธฐ [Spring] Spr..
blog.neonkid.xyz
Pointcut์ ์ธํฐํ์ด์ค ํํ๋ก ๋์ด ์์ง๋ง Spring AOP์์ ์ด๋ฏธ ๋ง์ ๊ตฌํ์ฒด๋ค์ด ๋ง๋ค์ด์ ธ ์๊ธฐ ๋๋ฌธ์ ์ผ๋ถ๋ฌ ์ฐ๋ฆฌ๊ฐ ์ปค์คํ ํฌ์ธํธ์ปท์ ๊ฐ๋ฐํ์ฌ ์ฌ์ฉํ ํ์๊ฐ ์์๋ค๊ณ ์ด์ผ๊ธฐ ํ์์ฃ .
์ด๋ฒ ๊ธ์์๋ ์ด ๊ตฌํ๋ 8๊ฐ์ ํฌ์ธํธ์ปท์ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
StaticMethodMatcherPointcut
๋จผ์ ํธ์ ํด๋์ค๋ถํฐ ์์ํด๋ณด๊ฒ ์ต๋๋ค. ์ถ์ StaticMethodMatcherPointcut ํด๋์ค๋ฅผ ์์ํ์ฌ ๊ฐ๋จํ ์ ์ ํฌ์ธํธ์ปท์ ์๋์ ๊ฐ์ด ๋ง๋ค์ด๋ด ๋๋ค.
import org.springframework.aop.support.StaticMethodMatcherPointcut; | |
/** | |
* Created by Neon K.I.D on 10/10/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
public class SimpleStaticPointcut extends StaticMethodMatcherPointcut { | |
@Override | |
public boolean matches(Method method, Class<?> targetClass) { | |
} | |
@Override | |
public ClassFilter getClassFilter() { | |
} | |
} |

StaticMethodMatcherPointcut ํด๋์ค๋ MethodMatcher ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ์ถ์ ํด๋์ค์ธ StaticMethodMatcher ํด๋์ค๋ฅผ ์์ํ๋ฏ๋ก matches ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
๋๋จธ์ง Pointcut ๊ตฌํ์ฒด๋ ์ด๋ฏธ ๊ตฌํ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ ๊ฒฝ์ฐ์ง ์์๋ ๋๋ฏ๋ก StaticMethodMatcherPointcut์ ๊ตฌํํ ๋๋ ์๋์ ๋ ๊ฐ์ง๋ง ์ ์ํ๋ฉด ๋ฉ๋๋ค.
- getClassFilter์ ์ํ๋ ํด๋์ค์ ๋ฉ์๋ ์ ์
- matches์ ์ํ๋ ๋ฉ์๋ ์ ์
matches๋ ํ์์ง๋ง getClassFilter๋ ํ์๊ฐ ์๋๋ฐ, ๊ฐ์ ์ด๋ฆ์ ๋ชจ๋ ํด๋์ค ๋ฉ์๋๊ฐ ์๋ ํน์ ํด๋์ค์ ๋ฉ์๋๋ง ์ ์ํ๊ณ ์ถ๋ค๋ฉด getClassFilter์ ์ํ๋ ํด๋์ค๋ฅผ ๋ฃ์ด์ ์ ์ํ ์ ์์ต๋๋ค.
/** | |
* Created by Neon K.I.D on 10/10/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
interface Programmer { | |
void programming(); | |
} | |
class JavaProgrammer implements Programmer { | |
@Override | |
public void programming() { | |
System.out.println("public static void main(String[] args) { }"); | |
} | |
} | |
class KotlinProgrammer implements Programmer { | |
@Override | |
public void programming() { | |
System.out.println("fun main() { }"); | |
} | |
} |
๊ฐ๋จํ ์์ ๋ฅผ ๋ณด๊ฒ ์ต๋๋ค. ๋์ผํ DefaultPointcutAdvisor๋ฅผ ์ฌ์ฉํ์ฌ ๋ ํด๋์ค์ ํ๋ก์๋ฅผ ์์ฑํ๊ณ JavaProgrammer ํด๋์ค์ programming() ๋ฉ์๋์๋ง ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
class SimpleStaticPointcut extends StaticMethodMatcherPointcut { | |
@Override | |
public boolean matches(Method method, Class<?> targetClass) { | |
return ("programming".equals(method.getName())); | |
} | |
@Override | |
public ClassFilter getClassFilter() { | |
// return new ClassFilter() { | |
// public boolean matches(Class<?> cls) { | |
// return (cls == JavaProgrammer.class); | |
// } | |
// } | |
return cls -> (cls == JavaProgrammer.class); | |
} | |
} |
matches ๋ฉ์๋์์ methd.getName()์ ์ด์ฉํด ์ค์ ๊ฐ์ฒด๊ฐ ํธ์ถํ๋ ๋ฉ์๋์ ์ด๋ฆ์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋ ์ด๋ฆ์ programming์ผ๋ก ์ ์ํ์ฌ ํด๋น ๋ฉ์๋์๋ง ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
์ถ๊ฐ๋ก getClassFilter ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ํน์ ํด๋์ค์์๋ง ์๋ํ๋๋ก ๊ตฌํํ ์๋ ์์ต๋๋ค.
class SimpleAdvice implements MethodInterceptor { | |
@Override | |
public Object invoke(MethodInvocation invocation) throws Throwable { | |
// Before | |
System.out.println(">> Invoking " + invocation.getMethod().getName()); | |
Object retVal = invocation.proceed(); | |
// After | |
System.out.println(">> Done\n"); | |
return retVal; | |
} | |
} |
์ด์ ์ด๋๋ฐ์ด์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค. SimpleAdvice๋ผ๋ ์ด๋ฆ์ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , MethodInterceptor๋ฅผ ๊ตฌํํฉ๋๋ค.
MethodInvocation ์ธ์์์๋ ์ฐ๋ฆฌ๊ฐ Pointcut์ ์ ์ํ๋ Method ์ด๋ฆ์ด ๋์ฌ ๊ฒ์ ๋๋ค. return true ์ฝ๋๋ฅผ ์์ฑํ์ฌ ์ด๋ค ๋ฉ์๋๋ Pointcut์ ๋์ํ๋๋ก ํ๋ค๋ฉด ๊ทธ ๋ฉ์๋ ์ด๋ฆ์ด ๋ํ๋ ๊ฒ์ ๋๋ค.
programming ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ ์ println์ ํ๊ณ , ํธ์ถํ๊ณ ๋ ๋ค, Done์ println ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
public class PointcutDemo { | |
public static void main(String[] args) { | |
JavaProgrammer johnMayer = new JavaProgrammer(); | |
KotlinProgrammer ericClapton = new KotlinProgrammer(); | |
Programmer proxyOne; | |
Programmer proxyTwo; | |
Pointcut pc = new SimpleStaticPointcut(); | |
Advice advice = new SimpleAdvice(); | |
Advisor advisor = new DefaultPointcutAdvisor(pc, advice); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.addAdvisor(advisor); | |
pf.setTarget(johnMayer); | |
proxyOne = (Programmer) pf.getProxy(); | |
pf = new ProxyFactory(); | |
pf.addAdvisor(advisor); | |
pf.setTarget(ericClapton); | |
proxyTwo = (Programmer)pf.getProxy(); | |
proxyOne.programming(); | |
proxyTwo.programming(); | |
} | |
} |
์ด์ SimpleAdvice์ SimpleStaticPointcut ํด๋์ค๋ฅผ ์ฌ์ฉํด ์ค์ Pointcut์ ์ด๋ป๊ฒ ์คํ์ํฌ ์ ์๋์ง ๋ณด๊ฒ ์ต๋๋ค. ์ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๋ ํด๋์ค ๋ชจ๋ DefaultPointcutAdvisor ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ๊ฐ๋จํ ํ ์คํธ ์ ํ๋ฆฌ์ผ์ด์ ์ธ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ๋ํ ๋ ํด๋์ค ๋ชจ๋ ๋์ผํ๊ฒ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ฏ๋ก ๊ตฌ์ ํด๋์ค(conctete class)๊ฐ ์๋ ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.

๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด SimpleAdvice๋ JavaProgrammer ํด๋์ค์ programming() ๋ฉ์๋์ ์ํด์๋ง ํธ์ถ๋์์ต๋๋ค. ์ด์ ๊ฐ์ด Pointcut์ผ๋ก ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ๋ ๋ฉ์๋๋ฅผ ๋งค์ฐ ๊ฐ๋จํ๊ฒ ์ ์ดํ ์ ์์ต๋๋ค.
DynamicMethodMatcherPointcut
๋์ ํฌ์ธํธ์ปท๋ ์ ์ ํฌ์ธํธ์ปท๊ณผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ด ํฌ๊ฒ ๋ค๋ฅด์ง ์์ต๋๋ค.
class SampleBean { | |
public void foo(int x) { | |
System.out.println("Invoked foo() with: " + x); | |
} | |
public void bar() { | |
System.out.println("Invoked bar()"); | |
} | |
} |
์ ์์ ๋ ๋์ ํฌ์ธํธ์ปท์ ์ ์ฉํ๊ธฐ ์ํ ํด๋์ค์ ๋๋ค. ์๋ฌด๋ฐ ์ธ์๋ ๋ฐ์ง ์๋ bar ๋ฉ์๋์ int ์ ์ ์ซ์ ํ ๊ฐ๋ฅผ ์ธ์๋ก ๋ฐ๋ foo ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
class SimpleDynamicPointcut extends DynamicMethodMatcherPointcut { | |
@Override | |
public boolean matches(Method method, Class<?> targetClass) { | |
System.out.println("Static check for " + method.getName()); | |
return "foo".equals(method.getName()); | |
} | |
@Override | |
public boolean matches(Method method, Class<?> targetClass, Object... args) { | |
System.out.println("Dynamic check for " + method.getName()); | |
int x = (Integer) args[0]; | |
return x != 100; | |
} | |
@Override | |
public ClassFilter getClassFilter() { | |
return cls -> (cls == SampleBean.class); | |
} | |
} |
StaticPointcut๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก foo() ๋ฉ์๋์๋ง ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ๋๋ฐ, ์ด์ ์ ์ฌ์ฉํ Programmer ์ธํฐํ์ด์ค์๋ ๋ค๋ฅด๊ฒ ์ ๋ฌ๋ int ์ธ์๊ฐ 100์ด ์๋ ๊ฒฝ์ฐ์๋ง ์ด ๋ฉ์๋์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํด๋ดค์ต๋๋ค.
์คํ๋ง์์๋ ๋์ ํฌ์ธํธ์ปท์ ์์ฑํ๋ ๋ฐ ํธ๋ฆฌํ ๊ธฐ๋ฐ ํด๋์ค์ธ DynamicMethodMatcherPointcut์ ์ ๊ณตํ๋๋ฐ, ์ด ํด๋์ค๋ MethodMatcher ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํ์ฒด๋ก ๊ฐ์ง๊ณ ์์ด ์๋์ ์ถ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
boolean matches(Method method, Class<?> targetClass, Object... args);
๋ํ, ์ ์ ๊ฒ์ฌ์ ๋์์ ์ ์ดํ๊ธฐ ์ํด ์๋์ ๋ฉ์๋๋ฅผ ํจ๊ป ๊ตฌํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
boolean matches(Method method, Class<?> targetClass);
์๋ณด๋ฉด ๋์ ๊ฒ์ฌ์ธ ์ ์ matches๋ง ๊ตฌํํด๋ ๋์ง๋ง ์ ์ ๊ฒ์ฌ์ธ ํ์์ matches๊น์ง๋ฅผ ๊ตฌํํ ์ด์ ๋ ์ ์ ๊ฒ์ฌ๋ฅผ ํตํด ํน์ ๋ฉ์๋๊ฐ ์ด๋๋ฐ์ด์ค๋ฅผ ํตํ์ง ์๋๋ก ํ๊ธฐ ์ํด์์ธ๋ฐ์.
์คํ๋ง์ ์ ์ ๊ฒ์ฌ ๋ฉ์๋๋ฅผ ์ํํ์ง ์์ผ๋ฉด ๋์ ๊ฒ์ฌ ๋ฉ์๋์์ ๋ชจ๋ ๋ฉ์๋์ ๋ํด ๋์ ๊ฒ์ฌ๋ฅผ ์ํํฉ๋๋ค. ๋ฐ๋ผ์ ํ์ํ์ง ์์ ๋ฉ์๋๊น์ง ๋ชจ๋ ๋์ ๊ฒ์ฌ๋ฅผ ์ํํ๊ธฐ ๋๋ฌธ์ ์์ ์๊ฐ์ด ๋ง์ด ๋ฐ์ํ๋๋ฐ, ์ด๋ฅผ ์ ์ ๊ฒ์ฌ๋ฅผ ํตํด ๋จผ์ ํ์ํ์ง ์์ ๋ฉ์๋๋ฅผ ๊ฒ์ฌํ๊ณ , ๊ฒ์ฌ ๊ฒฐ๊ณผ๊ฐ ์ผ์นํ์ง ์์ผ๋ฉด ๋ ์ด์ ๋์ ๊ฒ์ฌ๋ฅผ ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ธ ์ด์ ์ด ์๊น๋๋ค.
๊ฒ๋ค๊ฐ ์ ์ ๊ฒ์ฌ์ ๊ฒฐ๊ณผ๋ฅผ ํ ๋ฒ ์บ์ฑํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๋ฉ์๋์ ์ ์ ๊ฒ์ฌ ๊ฒฐ๊ณผ๊ฐ ์๋ ๊ฒฝ์ฐ ์ ์ ๊ฒ์ฌ ๋ํ ์ํํ์ง ์์ต๋๋ค.
์ต์ ํ๋ ํฌ์ธํธ์ปท์ ์ฌ์ฉํ๊ธฐ ์ํด ์ ๋ฆฌํ์๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋์ ํฌ์ธํธ์ปท์ ์ ์ ๊ฒ์ฌ๋ฅผ ์ด์ฉํ์ฌ ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์์ ๋ฉ์๋๋ฅผ ์ ์ .
- ๋์ ๊ฒ์ฌ๋ฅผ ์ด์ฉํ์ฌ ํ์คํ๊ฒ ์ด๋๋ฐ์ด์ค๋ฅผ ์ธ ๋ฉ์๋๋ง ์ฌ์ฉํ๋๋ก ๊ตฌํ
- getClassFilter๋ฅผ ์ด์ฉํด ํด๋์ค ๊ฒ์ฌ๋ฅผ ์ํ
์ค์ ๋ก ๋์ ํฌ์ธํธ์ปท์ด ๋์ํ๋ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- getClassFilter ๋ฉ์๋์์ ํด๋์ค ๊ฒ์ฌ ์ํ.
- ์ธ์๋ฅผ ๋ฐ์ง ์๋ matches ๋ฉ์๋ (์ ์ ๊ฒ์ฌ) ์ํ
- ์ธ์๋ฅผ ๋ฐ๋ matches ๋ฉ์๋ (๋์ ๊ฒ์ฌ) ์ํ
์ด๋ ๊ฒ ํด๋๋ฉด ํฌ์ธํธ์ปท์ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ๊ฐ ํจ์ฌ ์ฌ์์ง๋ฉฐ ์ข์ ์ฑ๋ฅ์ ๋ณด์ผ ์ ์์ต๋๋ค.
์ด์ ํฌ์ธํธ์ปท์ ์ง์ ์คํํด๋ณด๋ฉฐ ์ ์ํ ๊ณผ์ ์ ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
public class DynamicPointcutDemo { | |
public static void main(String[] args) { | |
SampleBean target = new SampleBean(); | |
Advisor advisor = new DefaultPointcutAdvisor(new SimpleDynamicPointcut(), new SimpleAdvice()); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(target); | |
pf.addAdvisor(advisor); | |
SampleBean proxy = (SampleBean) pf.getProxy(); | |
proxy.foo(1); | |
proxy.foo(10); | |
proxy.foo(100); | |
proxy.bar(); | |
proxy.bar(); | |
proxy.bar(); | |
} | |
} |
์ด๋๋ฐ์ด์ค๋ ์ ์ ํฌ์ธํธ์ปท์์ ์ฌ์ฉํ๋ SimpleAdvice๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ์ต๋๋ค.

์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ค์ํผ ์ฒ์ ๋ ๋ฒ์ foo() ๋ฉ์๋ ํธ์ถ์๋ง ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋์์ผ๋ฉฐ ์ฒ์์๋ ๋จผ์ ์ ์ ๊ฒ์ฌ๊ฐ ์ํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. (์ฐ๋ฆฌ๊ฐ ์ง์ ๊ตฌํํ์ง ์์๋ ๊ธฐ๋ณธ์ ์ธ Object ๋ฉ์๋๋ค๊น์ง ์ ๋ถ...)
์ฌ๊ธฐ์ ์ฃผ๋ชฉํด์ผํ ์ ์ foo() ๋ฉ์๋๋ ๋ชจ๋ ๋ฉ์๋๋ฅผ ๊ฒ์ฌํ๋ ์ด๊ธฐํ ๋จ๊ณ, ๋ฉ์๋๊ฐ ์ฒ์ ํธ์ถ๋๋ ๋จ๊ณ์์ ๋ ๋ฒ์ ์ ์ ๊ฒ์ฌ๋ฅผ ๋ฐ์๋ค๋ ๊ฒ์ ๋๋ค.
์ด์ฒ๋ผ ๋์ ํฌ์ธํธ์ปท์ ์ ์ ํฌ์ธํธ์ปท๋ณด๋ค ๋ ํฐ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ๋ฐํ์์ ์ฑ๋ฅ ์ค๋ฒํค๋๋ฅผ ๊ณ ๋ คํ์ฌ ๊ผญ ํ์ํ ๋๋ง ๋์ ํฌ์ธํธ์ปท์ ์ฌ์ฉํด์ผํ๋ค๋ ๊ฒ์ ๋ช ์ฌํฉ์๋ค.
NameMatchMethodPointcut
์ข ์ข ํฌ์ธํธ์ปท์ ๋ง๋ค ๋ ๋ฉ์๋์ ์๊ทธ๋์ฒ์ ๋ฐํ ํ์ ์ ์๊ด์์ด ๋ฉ์๋์ ์ด๋ฆ์ ๊ธฐ๋ฐ์ผ๋ก ์ ์ฉํ๊ณ ์ถ์ ๋๊ฐ ์์ต๋๋ค. ์ด ๋๋ StaticMethodMatcherPointcut์ ํ์ ํด๋์ค๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง ์ด์ ํ์ ํด๋์ค์ธ NameMatchMethodPointcut์ ์ฌ์ฉํด ๋ฉ์๋ ์ด๋ฆ ๋ชฉ๋ก๊ณผ ๋ฉ์๋ ์ด๋ฆ์ ๋งค์นญํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค.
๋ค๋ง ์ด ํฌ์ธํธ์ปท์ ๋ฉ์๋ ์๊ทธ๋์ฒ๋ ๊ณ ๋ คํ์ง ์๊ธฐ ๋๋ฌธ์ programming()๊ณผ programming(1.4) ๋ฉ์๋๊ฐ ์๋ค๋ฉด ๋ ๋ค programming์ด๋ผ๋ ์ด๋ฆ๊ณผ ๋งค์นญ๋ฉ๋๋ค.
class JavaProgrammer implements Programmer { | |
@Override | |
public void programming() { | |
System.out.println("public static void main(String[] args) { }"); | |
} | |
public void programming(IDE ide) { | |
System.out.println(ide + " Programming"); | |
} | |
public void test() { | |
System.out.println("Test"); | |
} | |
} |
์ ์ ํฌ์ธํธ์ปท์์ ์ฌ์ฉํ๋ JavaProgrammer ์์ ์ฝ๋์ programming() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ก๋ฉํ์ฌ ํน์ IDE๋ฅผ ์ฌ์ฉํด ํ๋ก๊ทธ๋๋ฐํ๊ณ ์๋ ๊ฒ์ ํํํด๋ณด๊ฒ ์ต๋๋ค.
์ด ์์ ์์ ํ๊ณ ์ ํ๋ ๊ฒ์ NameMatchMethodPointcut์ ์ด์ฉํด programming(), programming(IDE), test() ๋ฉ์๋์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ๋ ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ด ํฌ์ธํธ์ปท์ programming๊ณผ test ๋ผ๋ ์ด๋ฆ์ผ๋ก๋ง ๋งค์นญ๋ ๊ฒ์ ๋๋ค.
enum IDE { | |
ECLIPSE("Eclipse"), | |
INTELLIJ_IDEA("Intellij IDEA"), | |
VISUAL_STUDIO_CODE("Visual Studio Code"), | |
VIM("vim"); | |
private final String value; | |
IDE(String value) { | |
this.value = value; | |
} | |
public String toString() { | |
return value; | |
} | |
} |
IDE๋ ์ด๊ฑฐ์ฒด๋ก ํ๊ธฐํ์ฌ Eclipse๋ถํฐ Vim๊น์ง ๋ฃ์ด๋ณด๊ฒ ์ต๋๋ค.
import org.springframework.aop.Advisor; | |
import org.springframework.aop.framework.ProxyFactory; | |
import org.springframework.aop.support.DefaultPointcutAdvisor; | |
import org.springframework.aop.support.NameMatchMethodPointcut; | |
/** | |
* Created by Neon K.I.D on 10/29/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
public class NamePointcutDemo { | |
public static void main(String[] args) { | |
JavaProgrammer javaProgrammer = new JavaProgrammer(); | |
NameMatchMethodPointcut pc = new NameMatchMethodPointcut(); | |
pc.addMethodName("programming"); | |
pc.addMethodName("test"); | |
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice()); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(javaProgrammer); | |
pf.addAdvisor(advisor); | |
JavaProgrammer proxy = (JavaProgrammer) pf.getProxy(); | |
proxy.programming(); | |
proxy.programming(IDE.INTELLIJ_IDEA); | |
proxy.test(); | |
} | |
} |
NameMatchMethodPointcut์ ์ฌ์ฉํ ๋๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ addMethodName ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋งค์นญํ ๋ฉ์๋ ์ด๋ฆ์ ์ถ๊ฐํด์ค๋๋ค.

๊ทธ๋ฌ๋ฉด ํฌ์ธํธ์ปท์ ์ถ๊ฐํ programming, test ๋ ๊ฐ์ ๋ฉ์๋๊ฐ ๋์ค๋๋ฐ, ์ด ๋ ์ธ์๋ก ๋ฃ์ IDE ๊น์ง๋ ๊ฐ์ด ํฌํจ๋์ด ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
RegexpMethodPointcut
๋ฉ์๋ ์ด๋ฆ์ ์ ํํ ํน์ ํ ์ ์์ ๋๋ ํจํด์ ์ฌ์ฉํด๋ณผ ์ ์์ต๋๋ค. ์ผ์ ํ ํจํด์ ์ด๋ฆ์์๋ง ์ ํ์ฒ๋ฆฌ(์ด๋๋ฐ์ด์ค)๋ฅผ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด ์ ๊ท ํํ์ ํฌ์ธํธ์ปท์ธ JdkRegexMethodPointcut์ ์ฌ์ฉํด ์ ๊ท ํํ์ ๊ธฐ๋ฐ์ผ๋ก ๋ฉ์๋ ์ด๋ฆ์ ๋งค์นญ์ํฌ ์ ์์ต๋๋ค.
/** | |
* Created by Neon K.I.D on 10/29/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
class PythonProgrammer implements Programmer { | |
@Override | |
public void programming() { | |
System.out.println("if __name__ == '__main__':"); | |
} | |
public void asyncProgramming() { | |
System.out.println("asyncio.run()"); | |
} | |
public void test() { | |
System.out.println("pytest "); | |
} | |
} |
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ๊ณผ ๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ๋ชจ๋ ์ฌ์ฉํ ์ค ์๋ PythonProgrammer ํด๋์ค๋ฅผ ๊ตฌํํ์์ต๋๋ค. ์ด ์์ ๋ test ๋ฉ์๋๋ฅผ ์ ์ธํ ๋ชจ๋ programming ๋ฉ์๋์์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉ ํด๋ณด๊ณ ์ ํฉ๋๋ค.
์ ๊ท ํํ์ ๊ธฐ๋ฒ์ผ๋ก ํฌ์ธํธ์ปท์ ์ฌ์ฉํ๋ฉด ํด๋์ค์์ ์ด๋ฆ์ด programming์ด๋ผ๊ณ ์์ํ๋ ๋ชจ๋ ๋ฉ์๋์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค. (์ค๋ น ๋์๋ฌธ์๊ฐ ๋ค๋ฅด๋๋ผ๋)
public class RegexpPointcutDemo { | |
public static void main(String[] args) { | |
PythonProgrammer pythonProgrammer = new PythonProgrammer(); | |
JdkRegexpMethodPointcut pc = new JdkRegexpMethodPointcut(); | |
pc.setPattern("(?i).*programming.*"); | |
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice()); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(pythonProgrammer); | |
pf.addAdvisor(advisor); | |
PythonProgrammer proxy = (PythonProgrammer) pf.getProxy(); | |
proxy.programming(); | |
proxy.asyncProgramming(); | |
proxy.test(); | |
} | |
} |
์ ๊ท ํํ์์ ์ฌ์ฉํด ๋ฉ์๋ ์ด๋ฆ์ ๋งค์นญํ๋ ํฌ์ธํธ์ปท์ ์ฌ์ฉํ ๋๋ ์ธ์คํด์ค๋ฅผ ์์ฑํ ๋ค์ setPattern ๋ฑ์ ํจํด์ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ ์ฌ๋ฏธ์๋ ๊ฒ์ ํจํด์ธ๋ฐ, ๋ฉ์๋ ์ด๋ฆ์ ๋งค์นญํ ๋ ์คํ๋ง์ ํจํค์ง์ ํด๋์ค ์ด๋ฆ์ด ํฌํจ๋ ์ ์ฒด ๋ฉ์๋ ์ด๋ฆ๊ณผ ๋งค์นญํฉ๋๋ค. ๋ง์ฝ ํจํค์ง ์ด๋ฆ์ด xyz.neonkid.programmers.PythonProgrammer ๋ผ๋ฉด ์คํ๋ง์ xyz.neonkid.programmers.PythonProgrammer.programming๊ณผ ๋งค์นญํฉ๋๋ค. ๊ทธ๋์ ์ ๊ทํํ์ ์์ .*์ ์ฌ์ฉํ์ผ๋ฉฐ ๋์๋ฌธ์ ๊ตฌ๋ถ์ ํ์ง ์๊ธฐ ์ํด (?i)๋ฅผ ์ถ๊ฐํ์์ต๋๋ค. ๋ฐ๋ผ์ ํจํค์ง์ ์๋ ํด๋์ค์ ๋ฉ์๋์ ์ด๋ฆ์ ๋ชจ๋ ์์ง ๋ชปํ๋๋ผ๋ ์ฃผ์ด์ง ํจํค์ง ๋ด์ ๋ชจ๋ ๋ฉ์๋๋ฅผ ๋งค์นญํ ์ ์๋ค๋ ์ ์์ ๋งค์ฐ ์ ์ฉํ๊ฒ ์ธ ์ ์์ต๋๋ค.

๊ทธ๋ฌ๋ฉด test() ๋ฉ์๋๋ฅผ ์ ์ธํ programming()๊ณผ asyncProgramming() ๋ฉ์๋์๋ง ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋ฉ๋๋ค.
AspectJexpPointcut
JDK ์ ๊ท ํํ์ ์ธ์๋ AspectJ์ ํฌ์ธํธ์ปท ํํ์ ์ธ์ด๋ฅผ ์ด์ฉํด ํฌ์ธํธ์ปท์ ์ ์ธํ ์ ์์ต๋๋ค. ๋๋ถ๋ถ์ ์คํ๋ง ๊ฐ๋ฐ์ ๋ถ๋ค์ด ์ ๊ท ํํ์์ ์ฌ์ฉํ๋ค๋ฉด ์ด ํํ์์ ์ฌ์ฉํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์๋ํ๋ฉด ์คํ๋ง์์๋ @AspectJ ์ ๋ํ ์ด์ ๋ฐฉ์์ AOP ์ง์ ๊ธฐ๋ฅ์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
@AspectJ ์ ๋ํ ์ด์ ๋ฐฉ์ AOP ์ง์ ๊ธฐ๋ฅ์ ์ด์ฉํ ๋๋ AspectJ์ ํฌ์ธํธ์ปท ์ธ์ด๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๋ฐ๋ผ์ ํํ์ ์ธ์ด๋ฅผ ์ฌ์ฉํด ํฌ์ธํธ์ปท์ ์ฌ์ฉํ ๋๋ AspectJ ํฌ์ธํธ์ปท ํํ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋๋ค.
Spring์์ AspectJ ํฌ์ธํธ์ปท ํํ์์ ์ฌ์ฉํ๋ ค๋ฉด ํ๋ก์ ํธ์ classpath์ ๋ ๊ฐ์ AspectJ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ผ์ธ aspectjrt.jar์ aspectjweaver.jar๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค.
ext { | |
aspectjVersion = '1.9.2' | |
} | |
dependencies { | |
... | |
implementation 'org.aspectj:aspectjweaver:$aspectjVersion' | |
implementation 'org.aspectj:aspectjrt:$aspectjVersion' | |
... | |
} |
ํ์ง๋ง Spring boot์ spring-boot-starter-aop๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ด๋ฅผ ๋ณ๋๋ก ์ถ๊ฐํ ํ์๊ฐ ์์ด ๋ฐ๋ก AspectJexpPointcut์ ์ฌ์ฉํด ๋ณผ ์ ์์ต๋๋ค.
/** | |
* Created by Neon K.I.D on 10/29/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
public class AspectjexpPointcutDemo { | |
public static void main(String[] args) { | |
PythonProgrammer pythonProgrammer = new PythonProgrammer(); | |
AspectJExpressionPointcut pc = new AspectJExpressionPointcut(); | |
pc.setExpression("execution(* *programming* (..)) || execution(* *Programming* (..))"); | |
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice()); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(pythonProgrammer); | |
pf.addAdvisor(advisor); | |
PythonProgrammer proxy = (PythonProgrammer) pf.getProxy(); | |
proxy.programming(); | |
proxy.asyncProgramming(); | |
proxy.test(); | |
} | |
} |
RegexMethodPointcut๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์คํด์ค ์์ฑ ํ setExpression ๋ฉ์๋๋ฅผ ํตํด ํจํด์ ์ค์ ํ ํ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค๋ง JDK ์ ๊ท ํํ์๊ณผ๋ ์ ํ ๋ค๋ฅธ syntax๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ AspectJ expression์ ์ ๋ชจ๋ฅด๋ ๋ถ์ด๋ผ๋ฉด ์ด๋ฅผ ๋จผ์ ์ตํ๋ณด๊ณ ์ฌ์ฉํ์๋ ๊ฑธ ์ถ์ฒํฉ๋๋ค.
AnnotationMatchingPointcut
์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๋ํ ์ด์ ๊ธฐ๋ฐ์ผ ๋๋ ํฌ์ธํธ์ปท์ ์ ์ํ ๋ ํน์ ์ปค์คํ ์ ๋ํ ์ด์ ์ ๋ง๋ค๊ณ ์ด๋ฅผ ์ฌ์ฉํด ํฌ์ธํธ์ปท์ ์ ์ํ๊ณ ์ถ์ ๋๊ฐ ์์ต๋๋ค. ์ฆ, ํน์ ์ ๋ํ ์ด์ ์ด ์ ์ฉ๋ ๋ชจ๋ ๋ฉ์๋๋ ํ์ ์ ์ด๋๋ฐ์ด์ค ๋ก์ง์ ์ ์ฉํ๊ณ ์ถ์ ๋๊ฐ ์์ต๋๋ค.
์คํ๋ง์ ์ ๋ํ ์ด์ ์ ์ฌ์ฉํด ํฌ์ธํธ์ปท์ ์ ์ํ ์ ์๋ AnnotationMatchingPointcut ํด๋์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
/** | |
* Created by Neon K.I.D on 10/29/22 | |
* Blog : https://blog.neonkid.xyz | |
* Github : https://github.com/NEONKID | |
*/ | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target({ElementType.TYPE, ElementType.METHOD}) | |
public @interface AdviceRequired { | |
} |
@interface ํ์ ์ผ๋ก ์ฌ์ฉํด ์ธํฐํ์ด์ค๋ฅผ ์ ๋ํ ์ด์ ์ผ๋ก ์ ์ธํ๊ณ @Target ์ ๋ํ ์ด์ ์ ์ ๋ํ ์ด์ ์ ํ์ ๋ ๋ฒจ๊ณผ ๋ฉ์๋ ๋ ๋ฒจ๋ก ์ ์ฉํ ์ ์๊ฒ ์ ์ํฉ๋๋ค.
class JavaProgrammer implements Programmer { | |
@Override | |
public void programming() { | |
System.out.println("public static void main(String[] args) { }"); | |
} | |
@AdviceRequired | |
public void programming(IDE ide) { | |
System.out.println(ide + " Programming"); | |
} | |
public void test() { | |
System.out.println("Test"); | |
} | |
} |
์์์ ๊ตฌํํ JavaProgrammer ํด๋์ค์์ programming(IDE ide)์ ์กฐ๊ธ ์ ์ ๋ง๋ ์ ๋ํ ์ด์ ์ ์ ์ฉํด๋ด ๋๋ค.
public class AnnotationPointcutDemo { | |
public static void main(String[] args) { | |
JavaProgrammer javaProgrammer = new JavaProgrammer(); | |
AnnotationMatchingPointcut pc = AnnotationMatchingPointcut.forMethodAnnotation(AdviceRequired.class); | |
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice()); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(javaProgrammer); | |
pf.addAdvisor(advisor); | |
JavaProgrammer proxy = (JavaProgrammer) pf.getProxy(); | |
proxy.programming(IDE.INTELLIJ_IDEA); | |
proxy.programming(); | |
} | |
} |
forMethodAnnotation ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ ๋ํ ์ด์ ํ์ ์ ์ ๋ฌํด AnnotationMatchingPointcut ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ ์ง์ ํ ์ ๋ํ ์ด์ ์ด ์ ์ฉ๋ ๋ชจ๋ ๋ฉ์๋์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํ๋ค๋ ์ฝ๋์ ๋๋ค.
forClassAnnotation ๋ฉ์๋๋ฅผ ํธ์ถํด ํ์ ๋ ๋ฒจ์ ์ง์ ํ ์ ๋ํ ์ด์ ์ ์ ์ฉํ ์๋ ์์ต๋๋ค. ์กฐ๊ธ ์ ์ ๋ฉ์๋ ์์ @AdviceRequired๋ฅผ ํ์ง๋ง ํด๋์ค ์์ @AdviceRequired ํ ๊ฒฝ์ฐ ์ด ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค.

@AdviceRequired๋ฅผ ์ ์ programming(IDE ide)์๋ง ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
๋ง์น๋ฉฐ...
์ฌ๊ธฐ๊น์ง Pointcut์ ๋ํ ๊ฐ๋จํ ์ฌ์ฉ๋ฒ์ ์์๋ดค์ต๋๋ค.
์คํ๋ง์์๋ ๋ง์ Pointcut ๊ตฌํ์ฒด์ ๋ํด ํฌ์ธํธ์ปท ์ญํ ์ ํ๋ ํธ๋ฆฌํ Advisor ๊ตฌํ์ฒด๋ฅผ ์ ๊ณตํฉ๋๋ค. ์๋ฅผ ๋ค์ด DefaultPointcutAdvisor์ ํจ๊ป NameMatchMethodPointcut์ ์ฌ์ฉํ๋ ๋์ NameMatchMethodPointcutAdvisor๋ฅผ ์ด์ฉํ ์๋ ์์ต๋๋ค.
public class NamePointcutUsingAdvisor { | |
public static void main(String[] args) { | |
JavaProgrammer javaProgrammer = new JavaProgrammer(); | |
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor(new SimpleAdvice()); | |
advisor.addMethodName("programming"); | |
ProxyFactory pf = new ProxyFactory(); | |
pf.setTarget(javaProgrammer); | |
pf.addAdvisor(advisor); | |
JavaProgrammer proxy = (JavaProgrammer) pf.getProxy(); | |
proxy.programming(); | |
proxy.programming(IDE.INTELLIJ_IDEA); | |
} | |
} |
NameMatchMethodPointcut ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ ๋์ NameMatchMethodPointcutAdvisor ์ธ์คํด์ค์์ ํฌ์ธํธ์ปท ์์ธ ์ ๋ณด๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ NameMatchMethodPointcutAdvisor๋ Advisor์ด์ ํฌ์ธํธ์ปท ์ญํ ์ ํฉ๋๋ค. ๋ ๋ฐฉ์์ ๋ํ ํฐ ์ฑ๋ฅ ์ฐจ์ด๋ ์์ผ๋ฉฐ ๋ ๋ฒ์งธ ์ฝ๋๊ฐ ๋ ์งง๋ค๋ ๊ฒ์ ์์๊ฐ ์์ต๋๋ค. ํ์ง๋ง ์ข ๋ ๋ช ํํ๊ณ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ ๊ณผ์ ์ ๋ณด๊ณ ์ ํ๋ค๋ฉด ์ฒซ ๋ฒ์งธ ๋ฐฉ์์ด ์ข์ ์๋ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ธ ์ฑํฅ์ ๋ง๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค์ํ Advisor ๊ตฌํ์ฒด์ ๋ํ ์์ธํ ์ ๋ณด๋ ์๋์ ๋งํฌ์ธ org.springframework.aop.support ํจํค์ง์ JavaDoc์ ๋ณด๋ฉด ํ์ธํ ์ ์์ต๋๋ค.
org.springframework.aop.support (Spring Framework 5.3.23 API)
Package org.springframework.aop.support Description Convenience classes for using Spring's AOP API.
docs.spring.io