AspectJ Weaver๋ฅผ ์ฌ์ฉํ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์คํ๋ง AOP ๊ตฌํ ๋ฐฉ๋ฒ
AOP๋?
- Aspect Oriented Programming : ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ
- OOP ์ ๋ถ๋ฆฌ๋ ๊ฐ๋ ์ด ์๋๋ผ, OOP์ ๊ธฐ์ด๋ฅผ ๋๋ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์
- ํ๋์ ํ๋ก๊ทธ๋จ์ ๊ด์ (ํน์ ๊ด์ฌ์ฌ)๋ผ๋ ๋ ผ๋ฆฌ์ ์ธ ๋จ์๋ก ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ๋ ๊ฐ๋
- ๋ก๊น , ๊ฐ์ฌ, ์ ์ธ์ ํธ๋์ ์ , ๋ณด์, ์บ์ฑ ๋ฑ ๋ค์ํ ๊ณณ์์ ์ฌ์ฉ๋๋ค.
AOP ์ฉ์ด
- Joint Point : ๋ชจ๋์ด ์ฝ์ ๋์ด ๋์ํ๊ฒ ๋๋ ํน์ ์์น(๋ฉ์๋ ํธ์ถ ๋ฑ)
- Point Cut : ๋ค์ํ Joint Point ์ค์ ์ด๋ค ๊ฒ์ ์ฌ์ฉํ ์ง ์ ํ
- Advice : Joint Point์ ์ฝ์ ๋์ด ๋์ํ ์ ์๋ ์ฝ๋
- Weaving : Advice๋ฅผ ํต์ฌ ๋ก์ง ์ฝ๋์ ์ ์ฉํ๋ ๊ฒ
- Aspect : Point Cut + Advice
Spring AOP Advice ์ข ๋ฅ
- before : ๋ฉ์๋ ํธ์ถ ์ ์ ๋์ํ๋ Advice
- after-returning : ์์ธ ์์ด ํธ์ถ๋ ๋ฉ์๋์ ๋์์ด ์๋ฃ๋๋ฉด ๋์ํ๋ Advice
- after-throwing : ํธ์ถ๋ ๋ฉ์๋ ๋์ ์ค ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ๋์ํ๋ Advice
- after : ์์ธ ๋ฐ์ ์ฌ๋ถ์ ๊ด๊ณ์์ด ํธ์ถ๋ ๋ฉ์๋์ ๋์์ด ์๋ฃ๋๋ฉด ๋์ํ๋ Advice
- around : ๋ฉ์๋ ํธ์ถ ์ ๊ณผ ํ์ ๋์ํ๋ Advice
Spring AOP ๊ตฌํ
AspectJ Weaver๋ฅผ ์ฌ์ฉํ Spring AOP ๊ตฌํ ๋ฐฉ๋ฒ์ XML์ ์ด์ฉํ๋ ๊ฒ๊ณผ @AspectJ ์ ๋ ธํ ์ด์ ์ ์ด์ฉํ๋ ๊ฒ์ผ๋ก ๋๋๋ค.
๋ณธ ๊ธ์์๋ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ๊ตฌํ ๋ฐฉ๋ฒ์ ์ดํด๋ณธ๋ค.
๊ด๋ จ ๊ธ - AspectJ Weaver๋ฅผ ์ฌ์ฉํ XML ๊ธฐ๋ฐ์ ์คํ๋ง AOP ๊ตฌํ ๋ฐฉ๋ฒ
1) ๊ณตํต ์ฌํญ
โ AspectJ Weaver ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
โก ๊ด์ฌ์ฌ๋ก ์ค์ ํ ์ฝ๋ ์์ฑ
@Component
public class TestBean {
public int method1() {
System.out.println("method1 ํธ์ถ");
return 100;
}
}
๊ด์ฌ์ฌ๋ก ์ค์ ํ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
TestBean ํด๋์ค์ method1() ๋ฉ์๋ ํธ์ถ์ ๊ด์ฌ์ฌ๋ก ์ค์ ํ ๊ฒ์ด๋ค.
๋ค์ํ ์ผ์ด์ค๋ฅผ ํ ์คํธํ๊ธฐ ์ํด intํ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํดํ๋๋ก ํ์๋ค.
public class MainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean bean1 = ctx.getBean(TestBean.class);
int a1 = bean1.method1();
System.out.printf("a1 : %d\n", a1);
ctx.close();
}
}
main ๋ฉ์๋์์ ApplicationContext ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ TestBean ๋น ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์จ ๋ค TestBean ํด๋์ค์ method1() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
๐ฅ ์คํ ๊ฒฐ๊ณผ
method1 ํธ์ถ
a1 : 100
Spring AOP๋ฅผ ์ฌ์ฉํด method1()์ ํธ์ถ์ ๊ด์ฌ์ฌ๋ก ์ค์ ํ์ฌ method1() ํธ์ถ ์ , ํ์ ํน์ ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์๋๋ก ๊ตฌํํ ๊ฒ์ด๋ค.
โข Advisor ํด๋์ค ์์ฑ
import org.aspectj.lang.annotation.Aspect;
@Aspect
@Component
public class AdvisorClass {
}
Advice๋ค์ ๋ชจ์๋์ ๊ฒ์ Advisor๋ผ๊ณ ํ๋ค.
@Aspect ์ ๋ ธํ ์ด์ ์ ๋ถ์ฌ advisor ํด๋์ค๋ฅผ ์์ฑํ๋ค.
์ด ํด๋์ค์ method1()์ ํธ์ถ ์ , ํ์ ํธ์ถํ ๋ฉ์๋๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค.
2) ์ ๋ ธํ ์ด์ ์ ์ด์ฉํ ๊ตฌํ ๋ฐฉ๋ฒ
์คํ๋ง ์ค์ ํด๋์ค
@Configuration
@ComponentScan(basePackages = {"com.atoz_develop.beans", "com.atoz_develop.advisor"})
@EnableAspectJAutoProxy
public class BeanConfigClass {
}
์คํ๋ง ์ค์ ํด๋์ค์ @EnableAspectJAutoProxy๋ฅผ ๋ถ์ฌ์ค๋ค.
@Aspect๊ฐ ๋ถ์ด์๋ advisor ํด๋์ค์ ์ ๋
ธํ
์ด์
์ ๋ถ์ํด์ AOP ์
ํ
์ ํ๋๋ก ํ๋ ์ ๋
ธํ
์ด์
์ด๋ค.
์คํ๋ง XML ์ค์ ์ฌ์ฉ ์์๋ <aop:aspectj-autoproxy/>๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
๐ AspectJ Weaver ์ ๋ ธํ ์ด์ AOP ์ค์ ํ๊ธฐ
์คํ๋ง ์๋ฐ ์ค์ ์ฌ์ฉ ์ : @EnableAspectJAutoProxy
์คํ๋ง XML ์ค์ ์ฌ์ฉ ์ : <aop:aspectj-autoproxy/>
AOP๋ฅผ ์ ๋ ธํ ์ด์ ์ผ๋ก ์ค์ ํ๋ฏ๋ก ์คํ๋ง ์ค์ ํด๋์ค์ ํด์ค ๊ฒ์ ์ด๊ฒ ๋์ด๋ค.
AspectJ Weaver๋ฅผ ์ฌ์ฉํ XML ๊ธฐ๋ฐ์ AOP๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๊ณผ ๋ฌ๋ฆฌ AOP ์ค์ ์ ์คํ๋ง ์ค์ ํ์ผ์ ์์ฑํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด์ before, after, around, after-returning, after-throwing advice ๋ฉ์๋๋ฅผ ์ฐจ๋ก๋ก ๊ตฌํํ๊ณ ํ ์คํธํด๋ณด์.
โ Before Advice - ๋ฉ์๋ ํธ์ถ ์ ์ ๋์
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class AdvisorClass {
// before advice
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod ํธ์ถ");
}
}
advisor ํด๋์ค์์ @Before ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด before advice ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
@Before() ์์ execution ๋ช ์์๋ฅผ ์ฌ์ฉํด์ ํน์ ๊ด์ฌ์ฌ๋ฅผ ์ง์ ํ๋ค.
execution(* method1())๊ณผ ๊ฐ์ด ์ค์ ํ๋ฉด ๋ชจ๋ ํจํค์ง, ๋ชจ๋ ํด๋์ค์ method1() ๋ฉ์๋ ํธ์ถ์ด ๊ด์ฌ์ฌ๊ฐ ๋๋ค.
๐ ์ฐธ๊ณ - [AspectJ Weaver] execution ์ง์์ ์ค์ ๋ฐฉ๋ฒ ์ ๋ฆฌ
๐ฅ ์คํ ๊ฒฐ๊ณผ
beforeMethod ํธ์ถ
method1 ํธ์ถ
a1 : 100
โก After Advice - ์์ธ ๋ฐ์ ์ฌ๋ถ์ ๊ด๊ณ์์ด ํธ์ถ๋ ๋ฉ์๋์ ๋์์ด ์๋ฃ๋๋ฉด ๋์
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class AdvisorClass {
// before advice
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod ํธ์ถ");
}
// after advice
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod ํธ์ถ");
}
}
advisor ํด๋์ค์์ @After ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด after advice ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
๐ฅ ์คํ ๊ฒฐ๊ณผ
beforeMethod ํธ์ถ
method1 ํธ์ถ
afterMethod ํธ์ถ
a1 : 100
โข Around Advice - ๋ฉ์๋ ํธ์ถ ์ ๊ณผ ํ์ ๋์
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class AdvisorClass {
// before advice
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod ํธ์ถ");
}
// after advice
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod ํธ์ถ");
}
// around advice
@Around("execution(* method1())")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aroundMethod ํธ์ถ 1");
Object result = pjp.proceed();
System.out.println("aroundMethod ํธ์ถ 2");
return result;
}
}
advisor ํด๋์ค์์ @Around ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด around advice ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
์ด ๋๋ org.aspectj.lang.ProceedingJoinPoint๋ฅผ ๋ฉ์๋์ ์ธ์๋ก ๋ฐ์์ ์ด ๊ฐ์ฒด์ proceed()๋ฅผ ํธ์ถํ์ฌ ์์ ์ค๊ฐ์ ์๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ๋ค.
์๋ ๋ฉ์๋๊ฐ ๋ฆฌํด๊ฐ์ด ์์ ๊ฒฝ์ฐ Object ํ์ ์ผ๋ก ๋ฐ์์ ๋ฐํํ๋ค.
๐ฅ ์คํ ๊ฒฐ๊ณผ
aroundMethod ํธ์ถ 1
beforeMethod ํธ์ถ
method1 ํธ์ถ
aroundMethod ํธ์ถ 2
afterMethod ํธ์ถ
a1 : 100
โฃ After-Returning Advice - ์์ธ ์์ด ํธ์ถ๋ ๋ฉ์๋์ ๋์์ด ์๋ฃ๋๋ฉด ๋์
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class AdvisorClass {
// before advice
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod ํธ์ถ");
}
// after advice
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod ํธ์ถ");
}
// around advice
@Around("execution(* method1())")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aroundMethod ํธ์ถ 1");
Object result = pjp.proceed();
System.out.println("aroundMethod ํธ์ถ 2");
return result;
}
// after-returning advice
@AfterReturning("execution(* method1())")
public void afterReturningMethod() {
System.out.println("afterReturning ํธ์ถ");
}
}
advisor ํด๋์ค์์ @AfterReturning ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด after-returning advice ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
๐ฅ ์คํ ๊ฒฐ๊ณผ
aroundMethod ํธ์ถ 1
beforeMethod ํธ์ถ
method1 ํธ์ถ
aroundMethod ํธ์ถ 2
afterMethod ํธ์ถ
afterReturning ํธ์ถ
a1 : 100
โค After-Throwing Advice - ํธ์ถ๋ ๋ฉ์๋ ๋์ ์ค ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ๋์
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class AdvisorClass {
// before advice
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod ํธ์ถ");
}
// after advice
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod ํธ์ถ");
}
// around advice
@Around("execution(* method1())")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aroundMethod ํธ์ถ 1");
Object result = pjp.proceed();
System.out.println("aroundMethod ํธ์ถ 2");
return result;
}
// after-returning advice
@AfterReturning("execution(* method1())")
public void afterReturningMethod() {
System.out.println("afterReturning ํธ์ถ");
}
// after-throwing advice
@AfterThrowing("execution(* method1())")
public void afterThrowingMethod() {
System.out.println("afterThrowing ํธ์ถ");
}
}
advisor ํด๋์ค์์ @AfterThrowing ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด after-throwing advice ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค.
@Component
public class TestBean {
public int method1() {
System.out.println("method1 ํธ์ถ");
int a1 = 10 / 0; // ์์ธ ๋ฐ์
return 100;
}
}
ํ ์คํธ๋ฅผ ์ํด method1()์์ ์์ธ๋ฅผ ๋ฐ์์ํค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
๐ฅ ์คํ ๊ฒฐ๊ณผ
aroundMethod ํธ์ถ 1
beforeMethod ํธ์ถ
method1 ํธ์ถ
afterMethod ํธ์ถ
afterThrowing ํธ์ถ
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.atoz_develop.beans.TestBean1.method1(TestBean1.java:11)
at com.atoz_develop.beans.TestBean1$$FastClassBySpringCGLIB$$61d1459a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at com.atoz_develop.advisor.AdvisorClass.aroundMethod(AdvisorClass.java:32)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.atoz_develop.beans.TestBean1$$EnhancerBySpringCGLIB$$dba43ddc.method1(<generated>)
at com.atoz_develop.main.MainClass.main(MainClass.java:29)
Process finished with exit code 1
๊ด์ฌ์ฌ๋ก ์ค์ ํ method1() ํธ์ถ ์ค ์์ธ๊ฐ ๋ฐ์ํ์ after-returning advice ๋ฉ์๋ ๋์ after-throwing advice ๋ฉ์๋๊ฐ ํธ์ถ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ํ ์คํธ ํ method1()์์ ์์ธ๋ฅผ ๋ฐ์์ํค๊ธฐ ์ํด ์ถ๊ฐํ ์ฝ๋๋ฅผ ์ญ์ ํ๋ ๊ฒ์ ์์ง ๋ง์.
๊ด๋ จ ๊ธ
- AspectJ Weaver๋ฅผ ์ฌ์ฉํ XML ๊ธฐ๋ฐ์ ์คํ๋ง AOP ๊ตฌํ ๋ฐฉ๋ฒ
- [AspectJ Weaver] execution ์ง์์ ์ค์ ๋ฐฉ๋ฒ ์ ๋ฆฌ
References
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์คํ๋ง JDBC ํ๋ก๊ทธ๋๋ฐ - MyBatis ์ฐ๋ (0) | 2020.04.28 |
---|---|
์คํ๋ง JDBC ํ๋ก๊ทธ๋๋ฐ - JdbcTemplate (0) | 2020.04.27 |
AspectJ Weaver๋ฅผ ์ฌ์ฉํ XML ๊ธฐ๋ฐ์ ์คํ๋ง AOP ๊ตฌํ ๋ฐฉ๋ฒ (0) | 2020.04.27 |
[Spring] @Component ์ ๋ ธํ ์ด์ ๋ฐ ํจ๊ป ์ฌ์ฉํ๋ ์ ๋ ธํ ์ด์ ์ ๋ฆฌ (0) | 2020.04.25 |
[Spring] ์ ๋ ธํ ์ด์ ์ ์ด์ฉํ ๋น ์ค์ ๋ฐฉ๋ฒ ์ ๋ฆฌ (0) | 2020.04.24 |
๋๊ธ