ํต์ฌ์ ์ธ ๋น์ฆ๋์ค ๋ก์ง(ํต์ฌ ๊ด์ )์ผ๋ก๋ถํฐ ํก๋จ ๊ด์ฌ์ฌ(๋ถ๊ฐ๊ธฐ๋ฅ)๋ฅผ ๋ถ๋ฆฌํ์ฌ ๋ชจ๋ํํฉ๋๋ค. ์ฆ AOP๋ ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ฐ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํก๋จ ๊ด์ฌ์ฌ๋? ์ฌ๋ฌ ์๋น์ค์ ๊ฑธ์ณ์ ๋์ํด์ผ ํ๋ ์ฝ๋๋ฅผ ์๋ฏธํฉ๋๋ค. ํต์ฌ๊ธฐ๋ฅ์ด ์๋ ์ค๊ฐ์ ์ฝ์
๋๋ ๊ธฐ๋ฅ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.์ฅ์ :
๐ฆ AOP ์์
Calculator(ํฉํ ๋ฆฌ์ผ)
public interface Calculator {
long factorial(long num);
}
BasicCalculator(for๋ฌธ)
public class BasicCalculator implements Calculator{
@Override
public long factorial(long num) {
long result = 1;
for (int i = 1; i <= num; i++) {
result *= i;
}
return result;
}
}
RecursiveCalculator(์ฌ๊ทํจ์)
public class RecursiveCalculator implements Calculator{
@Override
public long factorial(long num) {
if(num == 0){
return 1;
}
return num * factorial(num -1);
}
}
๐ ์๊ตฌ์ฌํญ : ๋ ํด๋์ค์ ์คํ ์๊ฐ์ ๊ตฌํ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ฃผ์ธ์
๋ฌธ์ ์
๊ธฐ์กด ์ฝ๋์ ์์ ์ด ํ์ํ๊ณ ์ฝ๋ ์ค๋ณต ๋ฐ์ํฉ๋๋ค.ํด๊ฒฐ๋ฐฉ๋ฒ
ํ๋ก์: ์์ ์ด ํด๋ผ์ด์ดํธ๊ฐ ์ฌ์ฉํ๋ ค๊ณ ํ๋ ์ค์ ๋์์ธ ๊ฒ ์ฒ๋ผ ์์ฅํด์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ๋ฐ์์ฃผ๋ ๊ฒ์ ๋๋ค. (๋๋ฆฌ์ธ, ๋๋ฆฌ์)
ํ๋ก์ ํจํด ์ ์ฉ
public class ExecutionTimeCalculator implements Calculator{
// ๊ตฌํ์ฒด์ ์์กด์ฑ์ ์ฃผ์
๋ฐ์ ํ๋
private final Calculator delegate;
// ์ธ๋ถ์์ ๊ตฌํ์ฒด์ ์์กด์ฑ์ ์ฃผ์
public ExecutionTimeCalculator(Calculator calculator) {
this.delegate = calculator;
}
@Override
public long factorial(final long num) {
// ์คํ ์๊ฐ ์ธก์
long start = System.currentTimeMillis();
// ์ธ๋ถ์์ ์ฃผ์
๋ฐ์ ๊ฐ์ฒด์๊ฒ ์์
long result = delegate.factorial(num);
// ์คํ ์๊ฐ ์ธก์
long end = System.currentTimeMillis();
System.out.printf("%s์ factorial(%d) Execution Time > %d\n",
delegate.getClass().getSimpleName(),
num,
(end - start));
return result;
}
}
public class Main {
public static void main(String[] args) {
Calculator proxyCalculator1 = new ExecutionTimeCalculator(new BasicCalculator());
System.out.println(proxyCalculator1.factorial(20));
Calculator proxyCalculator2 = new ExecutionTimeCalculator(new RecursiveCalculator());
System.out.println(proxyCalculator2.factorial(20));
}
}
ExecutionTimeCalculator๋ฅผ ์์ฑํ๊ณ , ์์ฑ์๋ฅผ ํตํด BasicCalculator ๊ฐ์ฒด๋ฅผ ์ฃผ์
ํฉ๋๋ค.factorial(20)์ผ๋ก ํธ์ถํฉ๋๋ค.BasicCalculator๊ฐ ๋ฐ๋ ๊ฒ์ด ์๋๋ผ ExecutionTimeCalculator๊ฐ ์์ฒญ์ ๋ฐ์ต๋๋ค.delegate.factorial(num) : ExecutionTimeCalculator๋ ์ธ๋ถ์์ ์ฃผ์
๋ Calculator ๊ตฌํ์ฒด์ ๋ํด ํฉํ ๋ฆฌ์ผ ์ฐ์ฐ์ ์ง์ ์ํํ์ง ์๊ณ , ๋์ ์ ์ด๋ฅผ Calculator ๊ตฌํ์ฒด์๊ฒ ์์ํ์ฌ ์คํํฉ๋๋ค. ๋ฐ๋ผ์ ExecutionTimeCalculator๋ ํฉํ ๋ฆฌ์ผ ์ฐ์ฐ์ ๋ํ ์ฃผ๋์ ์ธ ์ญํ ์ ์ํํ๋ ๊ฒ์ด ์๋๋ผ, ๋จ์ํ ์ฃผ์ด์ง ์
๋ ฅ๊ฐ์ ๋ํด ์ฃผ์
๋ Calculator ๊ตฌํ์ฒด์๊ฒ ์ฐ์ฐ์ ์์ํ๋ ์ญํ ์ ํฉ๋๋ค.BasicCalculator๊ฐ ํฉํ ๋ฆฌ์ผ ์ฐ์ฐ์ ํ๊ณ ์ด ๊ฒฐ๊ณผ๊ฐ์ ๋ค์ ExecutionTimeCalculator์ ๋ฐํํ๊ณ ๋ค์ ์คํ ์๊ฐ์ ๊ตฌํ๊ณ ์คํ ์๊ฐ์ ์ถ๋ ฅํด์ค๋๋ค.
๋ฐ๋ผ์ AOP๋โ
- ํต์ฌ ๊ธฐ๋ฅ์ ๋ฐ๋ผ ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ๋ ๊ฒ
- ํต์ฌ ๊ธฐ๋ฅ์ ์ฝ๋๋ฅผ ์์ ํ์ง ์์ผ๋ฉด์ ๊ณตํต ๊ธฐ๋ฅ์ ๊ตฌํ์ ์ถ๊ฐํ๋ ๊ฒ
@Target : ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ถ์ฌํ ๋์์ ์ง์ ํฉ๋๋ค. ์ด๋ ๋์์ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์ ์ฉํ ์ง๋ฅผ ๋ช
์ํฉ๋๋ค.
@Advice : ํ๊ฒ์ ์ ๊ณตํ ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ด์ ๋ชจ๋์ ์ ์ํ๋ ์ด๋
ธํ
์ด์
์
๋๋ค. Advice๋ฅผ ์ ์ํ ๋, ์ด๋ค ๊ธฐ๋ฅ์ ํ๋์ง์ ์ด๋ ์์ ์ ์ ์ฉํ ๊ฒ์ธ์ง๋ฅผ ์ ์ํด์ผ ํฉ๋๋ค.
@JoinPoint : ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋ ์ ์๋ ์์น๋ฅผ ์ง์ ํฉ๋๋ค. ์ด๋ ์์ ์์ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์ ์ฉํ ์ง๋ฅผ ์ ์ํฉ๋๋ค.
@Pointcut : ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ ์กฐ์ธ ํฌ์ธํธ๋ฅผ ์ ๋ณํ๋ ์์
์ ์ ์ํ๋ ์ด๋
ธํ
์ด์
์
๋๋ค. ๋ถ๊ฐ ๊ธฐ๋ฅ์ด ์ ์ฉ๋ ๋ฉ์๋๋ฅผ ์ ๋ณํ๋ ์ฉ๋๋ก ์ฌ์ฉ๋ฉ๋๋ค.
@Aspect : ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ํ๋ Advice์ ์ด๋ Join Point(์ฐ๊ฒฐ ์ง์ )์์ ํด๋น Advice๊ฐ ์คํ๋ ์ง๋ฅผ ๊ฒฐ์ ํ๋ Pointcut์ ์ ์ธํ ์ ์์ต๋๋ค.
@Weaving : ์กฐ์ธ ํฌ์ธํธ์์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ ์ํ๋ ์ด๋
ธํ
์ด์
์
๋๋ค. ์ด๋ป๊ฒ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์กฐ์ธ ํฌ์ธํธ์ ์ ์ฉํ ์ง๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.@After : ๋ฉ์๋๊ฐ ๋ฐํ๋๊ฑฐ๋ ์์ธ ์ํฉ์ด ๋ฐ์ํ ์ดํ์ ํธ์ถ๋ฉ๋๋ค.@AfterReturning : ๋ฉ์๋๊ฐ ๋ฐํ๋ ์ดํ์ ํธ์ถ๋ฉ๋๋ค.@AfterThrowing : ๋ฉ์๋๊ฐ ์์ธ ์ํ์ ๋ฐ์์ํจ ์ดํ์ ํธ์ถ๋ฉ๋๋ค.@Before : ๋ฉ์๋๊ฐ ํธ์ถ๋๊ธฐ ์ด์ ์ ํธ์ถ๋ฉ๋๋ค.@Around : ๋ฉ์๋์ ํธ์ถ ์ ๊ณผ ํธ์ถ์ด ์๋ฃ๋๊ณ ๋ฐํ๋๊ฑฐ๋ ์์ธ ์ํฉ ์ดํ์ ํธ์ถ๋ฉ๋๋ค.BasicCalculator ๋น ๋ฑ๋ก
@Component
public class BasicCalculator implements Calculator{
@Override
public long factorial(long num) {
long result = 1;
for (int i = 1; i <= num; i++) {
result *= i;
}
return result;
}
}
RecursiveCalculator ๋น ๋ฑ๋ก
@Component
public class RecursiveCalculator implements Calculator{
@Override
public long factorial(long num) {
if(num == 0){
return 1;
}
return num * factorial(num -1);
}
}
ExecutionTimeAspect - AOP ๊ตฌํ
@Component //๋น ๋ฑ๋ก
@Aspect //AOP ๊ตฌํ
public class ExecutionTimeAspect {
@Pointcut("execution(* fact*(..))") //๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉํ ๋์(fact์ด๋ฆ ๋ค์ด๊ฐ) ์ค์
private void publicTarget(){}
// ํ๊น ํธ์ถ ์ , ํ์ ์คํ ์๊ฐ ์ธก์
@Around("publicTarget()") // ํฌ์ธํธ์ปท ์ฐธ์กฐ
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable{
long start = System.currentTimeMillis(); // ์์ ์๊ฐ ์ฒดํฌ
try {
Object result = joinPoint.proceed(); // ํ์ผ ํธ์ถ
return result;
} finally {
long finish = System.currentTimeMillis(); // ๋๋๋ ์๊ฐ ์ฒดํฌ
Signature signature = joinPoint.getSignature();
System.out.printf("%s.%s(%s) ์คํ์๊ฐ : %d \n",
joinPoint.getTarget().getClass().getSimpleName(),
signature.getName(),
Arrays.toString(joinPoint.getArgs()),
(finish-start));
}
}
}
@Component : ๋น์ผ๋ก ๋ฑ๋กํฉ๋๋ค.
@Aspect : Aspect ์ ๋ํ
์ด์
์ผ๋ก, ํด๋น ํด๋์ค๊ฐ Aspect๋ก ๋์ํจ์ ๋ํ๋
๋๋ค. Aspect๋ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ์ ์ฉํ ๋์์ ์ ์ํ๊ณ , ์ด์ ๋ํ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
@Pointcut("execution(* fact*(..))") : ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋ ๋์์ ์ง์ ํ๋ ํฌ์ธํธ์ปท์ ์ ์ํ๋ ์ด๋
ธํ
์ด์
์
๋๋ค. ์ฌ๊ธฐ์๋ ์ด๋ฆ์ด "fact"์ผ๋ก ์์ํ๋ ๋ฉ์๋๋ค์ ๋์์ผ๋ก ์ง์ ํฉ๋๋ค.
private void publicTarget() {} : ์์์ ์ ์ํ ํฌ์ธํธ์ปท์ ์ฌ์ฉํ๊ธฐ ์ํ ๋ฉ์๋์
๋๋ค. ์ด ๋ฉ์๋๋ ์ค์ ๋ก ํธ์ถ๋์ง ์์ผ๋ฉฐ, ํฌ์ธํธ์ปท์ ์ฐธ์กฐํ๊ธฐ ์ํ ์ฉ๋๋ก ์ฌ์ฉ๋ฉ๋๋ค.
@Around("publicTarget()") : ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ํ๋ ์ด๋
ธํ
์ด์
์ผ๋ก, ๋ฉ์๋ ์คํ ์ ๊ณผ ํ์ ๊ณตํต ๊ธฐ๋ฅ์ ์ ์ฉํ๋ Around ์ด๋๋ฐ์ด์ค๋ฅผ ์ง์ ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์์์ ์ ์ํ ํฌ์ธํธ์ปท์ ์ฌ์ฉํ์ฌ ๋ฉ์๋ ํธ์ถ ์ ํ์ ์ด๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํฉ๋๋ค.
์ด๋ฌํ ๋ฐฉ์์ผ๋ก ์์ Aspect๋ fact๋ก ์์ํ๋ ๋ฉ์๋์ ์คํ ์๊ฐ์ ์ธก์ ํ์ฌ ์ถ๋ ฅํ๋ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
@SpringBootTest
public class ExecutionTimeAspectTest {
@Autowired
private Calculator basicCalculator;
@Autowired
private Calculator recurCalculator;
@Test
public void test(){
long factorialAnswer = basicCalculator.factorial(5);
System.out.printf("factorial ๊ฒฐ๊ณผ : %d \n", factorialAnswer);
System.out.printf("์คํ๋ ๊ฐ์ฒด : %s \n", basicCalculator.getClass().getName());
System.out.println("=======================================");
long factorialAnswer2 = recurCalculator.factorial(5);
System.out.printf("factorial ๊ฒฐ๊ณผ : %d \n", factorialAnswer2);
System.out.printf("์คํ๋ ๊ฐ์ฒด : %s \n", recurCalculator.getClass().getName());
}
}