ํฌ์ธํธ์ปท (Pointcut)
์ด๋์ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉํ ์ง ๋ง์ง๋ฅผ ํ๋จํ๋ ํํฐ๋ง ๋ก์ง์ ๋๋ค.
ํฌ์ธํธ์ปท์ ClassFilter์ MathodMatcher๋ก ์ด๋ฃจ์ด์ง๋๋ค.
ClassFilter๋ ํด๋์ค์ ๋ํ ํํฐ๋ง์ ๋ด๋นํ๋ฉฐ, MathodMatcher๋ ๋ฉ์๋์ ๋ํ ํํฐ๋ง์ ๋ด๋นํฉ๋๋ค.
์ด๋๋ฐ์ด์ค (Advice)
ํ๋ก์๊ฐ ํธ์ถํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ๋๋ค.
์ด๋๋ฐ์ด์ (Advisor)
ํ๋์ ํฌ์ธํธ์ปท๊ณผ ํ๋์ ์ด๋๋ฐ์ด์ค๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
์ฝ๊ฒ ์ธ์ฐ๊ธฐ
์ถฉ๊ณ ํ๋ ์ฌ๋(Advisor)์ ๋๊ตฌ(Pointcut)์๊ฒ ์ด๋ค ์ถฉ๊ณ (Advice)๋ฅผ ํด์ผ ํ ์ง ์๊ณ ์์ต๋๋ค.
์ด๋๋ฐ์ด์ค ๋ง๋ค๊ธฐ
๋ค์ ๊ฒ์๊ธ(https://ttl-blog.tistory.com/862)์์ ๋ง๋ ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค.
class TimeAdvice : MethodInterceptor{
val log = logger<TimeAdvice>()
override fun invoke(invocation: MethodInvocation): Any? {
val startTime = System.currentTimeMillis()
val result = invocation.proceed()
val endTime = System.currentTimeMillis()
log.info("resultTime = {}", endTime - startTime)
return result
}
}
interface ServiceInterface {
fun call()
}
class ServiceImpl : ServiceInterface {
override fun call() {
println("ServiceImpl.call()!@!!!!!")
}
}
์ด๋๋ฐ์ด์ ๋ง๋ค๊ธฐ
class AdvisorTest {
@Test
fun advisorTest() {
val target = ServiceImpl()
val proxyFactory = ProxyFactory(target)//target ์ค์
val pointcut = Pointcut.TRUE //ํญ์ ์ฐธ์ธ ํฌ์ธํธ์ปท -> ์ด๋์๋ ์ ์ฉ๋๋ ํฌ์ธํธ์ปท
val advisor = DefaultPointcutAdvisor(pointcut, TimeAdvice())
proxyFactory.addAdvisor(advisor)//advisor ์ค์
val proxy = proxyFactory.proxy as ServiceInterface
proxy.call()
}
}
ํฌ์ธํธ์ปท ๋ง๋ค๊ธฐ
์ผ๋ฐ์ ์ผ๋ก๋ ์คํ๋ง์ด ๋ง๋ค์ด๋ ๊ตฌํ์ฒด๋ฅผ ์ฌ์ฉํ์ง๋ง, ํ์ต ์ฐจ์์์ ์ง์ ๋ง๋ค์ด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
class MyPointcut : Pointcut {
override fun getClassFilter(): ClassFilter {
return ClassFilter.TRUE //class๋ ์๊ด์์ด ์๋ํจ
}
override fun getMethodMatcher(): MethodMatcher {
return MyMethodMatcher()
}
}
class MyMethodMatcher : MethodMatcher{
override fun matches(method: Method, targetClass: Class<*>): Boolean {
//noLog๊ฐ ์๋ ๊ฒฝ์ฐ ํธ์ถ
val result = !method.name.equals("noLog")
println("ํฌ์ธํธ์ปท ํธ์ถ method = {${method.name}}, targetClass={${targetClass}}")
println("ํฌ์ธํธ์ปท ๊ฒฐ๊ณผ = {${result}}")
//noLog๊ฐ ์๋ ๊ฒฝ์ฐ ํธ์ถ
return result
}
//== ๋ฐํ์ ์ ์ฒดํฌํด์ผ ํ๋ ๊ฒฝ์ฐ ๊ตฌํ ==//
//isRuntime() ์ด true๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ ํธ์ถ
override fun matches(method: Method, targetClass: Class<*>, vararg args: Any?): Boolean {
return false
}
override fun isRuntime(): Boolean {
return false
}
}
@Test
fun advisorTest2() {
val target = ServiceImpl()
val proxyFactory = ProxyFactory(target)//target ์ค์
val pointcut = MyPointcut()
val advisor = DefaultPointcutAdvisor(pointcut, TimeAdvice())
proxyFactory.addAdvisor(advisor)//advisor ์ค์
val proxy = proxyFactory.proxy as ServiceInterface
proxy.call()
}
์คํ๋ง์์ ์ ๊ณตํด์ฃผ๋ ํฌ์ธํธ์ปท
์์
@Test
fun advisorTest3() {
val target = ServiceImpl()
val proxyFactory = ProxyFactory(target)//target ์ค์
val pointcut = NameMatchMethodPointcut()
pointcut.setMappedName("call")//์ ์ฉํ ๋ฉ์๋ ์ด๋ฆ ์ค์
val advisor = DefaultPointcutAdvisor(pointcut, TimeAdvice())
proxyFactory.addAdvisor(advisor)//advisor ์ค์
val proxy = proxyFactory.proxy as ServiceInterface
proxy.call()
}
- NameMatchMethodPointcut : ๋ฉ์๋ ์ด๋ฆ์ ๊ธฐ๋ฐ์ผ๋ก ๋งค์นญํฉ๋๋ค. ๋ด๋ถ์์๋ PatternMatchUtils ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- JdkRegexpMethodPointcut : JDK ์ ๊ท ํํ์์ ๊ธฐ๋ฐ์ผ๋ก ํฌ์ธํธ์ปท์ ๋งค์นญํฉ๋๋ค.
- TruePointcut : ํญ์ ์ฐธ์ ๋ฐํํฉ๋๋ค.
- AnnotationMatchingPointcut : ์ ๋ ธํ ์ด์ ์ผ๋ก ๋งค์นญํฉ๋๋ค.
- AspectJExpressionPointcut : aspectJ ํํ์์ผ๋ก ๋งค์นญํฉ๋๋ค.
AspectJExpressionPointcut์ด ์ ์ผ ์ค์ํ๋ฉฐ, ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
์ฌ๋ฌ ์ด๋๋ฐ์ด์ ๋ฅผ ์ ์ฉํ๋ ๊ฒฝ์ฐ
์ฌ๋ฌ ์ด๋๋ฐ์ด์ ๋ฅผ ์ ์ฉํ๋ค๊ณ ํ๋๋ผ๋, ํ๋ก์๋ ๋จ ํ๋๋ง ๋ง๋ญ๋๋ค.
ํ๋์ ํ๋ก์์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ ๊ฐ ์ ์ฉ๋๋ ๊ฒ์ด์ง, ์ด๋๋ฐ์ด์ ์ ์ ๋งํผ ํ๋ก์๊ฐ ์์ฑ๋๋ ๊ฒ์ด ์๋๋๋ค.
Reference
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop
'๐๏ธ Spring > AOP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[AOP] ์คํ๋ง AOP ๊ตฌํ๋ฐฉ๋ฒ (0) | 2022.08.02 |
---|---|
[AOP] @Aspect (0) | 2022.08.01 |
[AOP] ๋น ํ์ฒ๋ฆฌ๊ธฐ(BeanPostProccessor)์AnnotationAwareAspectJAutoProxyCreator (0) | 2022.08.01 |
[AOP] ํ๋ก์ ํฉํ ๋ฆฌ (0) | 2022.08.01 |
[Spring] AOP - ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ (0) | 2022.02.12 |