[Spring] ์คํ๋ง AOP ๊ฐ๋ ์ดํด ๋ฐ ์ ์ฉ ๋ฐฉ๋ฒ
1. AOP(Aspect Oriented Programming)
Spring์ Spring Triangle์ด๋ผ๊ณ ๋ถ๋ฅด๋ ์ธ ๊ฐ์ง ๊ฐ๋ ์ ์ ๊ณตํด์ค๋ค. ๊ฐ๊ฐ IoC, AOP, PSA๋ฅผ ์ผ์ปซ๋๋ค.
AOP๋ Aspect Oriented Programming์ ์ฝ์๋ก '์ธก๋ฉด/์์ ์งํฅ์ ์ธ ํ๋ก๊ทธ๋๋ฐ'์ด๋ผ๋ ์๋ฏธ์ด๋ค.
'์ธก๋ฉด/์์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ'์ด ๋ฌด์์ ์๋ฏธํ๋๊ฐ?
class A {
method a() {
AAAA
method a๊ฐ ํ๋ ์ผ๋ค
BBBB
}
method b() {
AAAA
method b๊ฐ ํ๋ ์ผ๋ค
BBBB
}
}
class B {
method c() {
AAAA
method c๊ฐ ํ๋ ์ผ๋ค
BBBB
}
}
|
cs |
์์ ๊ฐ์ด ๋์ผํ ์ผ์ ํ๋ ์ฝ๋ AAAA, BBBB๊ฐ ์ฌ๊ธฐ์ ๊ธฐ์ ์ฌ์ฉ๋๊ณ ์ด๋ ๊ฒ ํฉ์ด์ ธ์์ผ๋ฉด ์ฝ๋ ๋ณ๊ฒฝ์ด ํ์ํ ๊ฒฝ์ฐ ์ผ์ผ์ด ๋ค ์ฐพ์์ ๋ฐ๊ฟ์ผํ๋ค.
AOP๋ ๊ทธ๋ ๊ฒ ํ์ง ์๊ณ ์ฌ๋ฌ๊ตฐ๋ฐ์ ์ฌ์ฉ๋๋ ์ค๋ณต๋๋ ์ฝ๋๋ฅผ ๋ผ์ด๋ด์ ๋ถ๋ฆฌํ๊ณ , method a, b, c๋ ์์ ์ด ํด์ผํ ์์ ๋ง ๊ฐ๊ณ ์์๋ ๊ฐ๋ ์ด๋ค.
์ฌ๊ธฐ์ '์ฌ๋ฌ๊ตฐ๋ฐ์ ์ฌ์ฉ๋๋ ์ค๋ณต๋๋ ์ฝ๋'๊ฐ AOP์์ ๋งํ๋ 'aspect'๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
2. ํ๋ก์ ํจํด
Spring AOP๋ ํ๋ก์ ํจํด์ด๋ผ๋ ๋์์ธ ํจํด์ ์ฌ์ฉํด์ AOP ํจ๊ณผ๋ฅผ ๋ธ๋ค.
ํ๋ก์ ํจํด์ ์ฌ์ฉํ๋ฉด ์ด๋ค ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ค ํ ๋ ๊ธฐ์กด ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์๋ค.
์ด๋ค ํด๋์ค๊ฐ Spring AOP์ ๋์์ด๋ผ๋ฉด ๊ทธ ๊ธฐ์กด ํด๋์ค์ ๋น์ด ๋ง๋ค์ด์ง๋ Spring AOP๊ฐ ํ๋ก์(๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ํด๋์ค)๋ฅผ ์๋์ผ๋ก ๋ง๋ค๊ณ ์๋ณธ ํด๋์ค ๋์ ํ๋ก์๋ฅผ ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ณธ ํด๋์ค๊ฐ ์ฌ์ฉ๋๋ ์ง์ ์์ ํ๋ก์๋ฅผ ๋์ ์ฌ์ฉํ๋ค.
Spring์ PetClinic ์์ ์์ OwnerRepository ์ธํฐํ์ด์ค์ @Transactional ์ ๋ ธํ ์ด์ ์ด ์ด์ ํด๋นํ๋ค.
@Transactional ์ ๋ ธํ ์ด์ ์ด ๋ถ์ด์์ผ๋ฉด OwnerRepository ํ์ ์ ํ๋ก์๊ฐ ์๋ก ๋ง๋ค์ด์ง๊ณ Spring AOP์ ์ํด ์๋์ผ๋ก ์์ฑ๋๋ OwnerRepository์ ํ๋ก์์๋ @Transactional ์ ๋ ธํ ์ด์ ์ด ์ง์ํ๋ ์ฝ๋๊ฐ ์ฝ์ ๋๋ค.
@Transactional ์ ๋ ธํ ์ด์ ์ ์ํด ์ถ๊ฐ๋๋ ๊ธฐ๋ฅ์ ๋ค์๊ณผ ๊ฐ๋ค.
JDBC์์ ํธ๋์ญ์ ์ฒ๋ฆฌ๋ฅผ ํ๋ ค๋ฉด SQL ์คํ๋ฌธ ์๋ค์ setAutoCommit()์ commit()/rollback() ์ฝ๋๊ฐ ํญ์ ๋ถ๋๋ฐ @Transactional ์ ๋ ธํ ์ด์ ์ ํ๋ก์์ ์๋์ผ๋ก ๊ทธ ์ฝ๋๋ฅผ ๋ฃ์ด์ ๋ฐ๋ณต, ์ค๋ณต๋๋ ์ฝ๋๋ฅผ ์๋ตํ ์ ์๊ฒํ๋ ๊ฒ์ด๋ค.
์ด๋ก ์ธํด ๊ฐ๋ฐ์๋ ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ ์ ์๊ฒ ๋๋ค.
3. Spring AOP ์ ์ฉ ์์
Spring์ด ์ ๊ณตํ๋ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ AOP๋ฅผ ์ง์ ์ ์ฉํด๋ณด์.
Spring PetClinic ์์ ์ OwnerController์ ๋ฉ์๋๋ค์ ๋ฉ์๋ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๊ฒ์ด๋ค.
- [Spring] ์คํ๋ง ์์ ํ๋ก์ ํธ PetClinic ๋น๋ ๋ฐ ์คํํ๊ธฐ
์ฐ์ ์ฑ๋ฅ์ ์ธก์ ํ๊ณ ์ ํ๋ ๋ฉ์๋์ @LogExecutionTime ์ ๋ ธํ ์ด์ ์ ๋ถ์ธ๋ค.
@LogExecutionTime์ ์ ๊ณต๋๋ ์ ๋ ธํ ์ด์ ์ด ์๋ ์๋ก ์ ์ํด์ผํ๋ ์ ๋ ธํ ์ด์ ์ด๋ฏ๋ก ์ง๊ธ์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
Alt + Enter๋ฅผ ๋๋ฌ quick fixes๋ฅผ ๋์ฐ๊ณ Create annotation 'LogExecutionTime'์ ํด๋ฆญํ๋ค.
OK๋ฅผ ํด๋ฆญํ๋ค.
๋น ์ ๋ ธํ ์ด์ ์ด ๋ง๋ค์ด์ก๋ค.
์๋์ ๊ฐ์ด ์ ๋ ธํ ์ด์ ์ ์ ์ํ๊ณ ๋ช๊ฐ์ง ์ค์ ์ ์ถ๊ฐํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
|
package org.springframework.samples.petclinic.owner;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
|
cs |
@Target(ElementType.METHOD)
์ ๋ ธํ ์ด์ ์ ๋ฉ์๋์ ์ฌ์ฉํ ๊ฒ์ด๋ผ๊ณ ์ค์ ํ๋ค.
@Retention(RetentionPolicy.RUNTIME)
์ ๋ ธํ ์ด์ ์ด RUNTIME๊น์ง ์ ์ง๋๋๋ก ์ค์ ํ๋ค.
์ด๋ค ๋ฉ์๋์ AOP๋ฅผ ์ ์ฉํ ๊ฑด์ง ์๋ ค์ฃผ๋ ์ ๋ ธํ ์ด์ ์ ์ ์ํ์๋ค.
์ด์ ํด๋น ๋ฉ์๋์ ์ด๋ค ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๊ฒ์ธ์ง๋ฅผ ์๋ ค์ฃผ๋ ์ค์ aspect๋ฅผ ๊ตฌํํด์ผํ๋ค.
๊ฐ์ ํจํค์ง์ LogAspect ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package org.springframework.samples.petclinic.owner;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Component
@Aspect
public class LogAspect {
Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// @LogExecutionTime ์ ๋
ธํ
์ด์
์ด ๋ถ์ด์๋ ํ๊ฒ ๋ฉ์๋๋ฅผ ์คํ
Object proceed = joinPoint.proceed();
stopWatch.stop();
logger.info(stopWatch.prettyPrint());
return proceed; // ๊ฒฐ๊ณผ ๋ฆฌํด
}
}
|
cs |
Logger logger = LoggerFactory.getLogger(LogAspect.class);
slf4j๋ก ๋ก๊ฑฐ๋ฅผ ๋ง๋ ๋ค.
@Around("@annotation(LogExecutionTime)")
์ด ์ ๋ ธํ ์ด์ ์ ๋ถ์ธ ๋ฉ์๋์์๋ ProceedingJoinPoint ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์ ์๋ค.
์ ๋ ธํ ์ด์ ์ value๋ฅผ "@annotation(LogExecutionTime)"๋ก ์ง์ ํจ์ผ๋ก์
joinPoint๋ @LogExecutionTime๋ฅผ ๋ถ์ธ ํ๊ฒ ๋ฉ์๋๋ฅผ ์๋ฏธํ๊ฒ ๋๋ค.
Object proceed = joinPoint.proceed();
ํ๊ฒ ๋ฉ์๋๋ฅผ ์คํํ๋ค.
์ด ๋ผ์ธ ์ ๋ค๋ก StopWatch๋ฅผ ์ด์ฉํ ๋ฉ์๋ ์ฑ๋ฅ ์ธก์ ์ฝ๋๋ฅผ ๋ฃ์ด์ค๋ค.
์ดํ๋ฆฌ์ผ์ด์ ์ ์คํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด์.
์์ ๊ฐ์ด OwnerController์ ๋ฉ์๋ ์คํ ์ LogAspect์ ์ถ๊ฐํ ๋ฉ์๋ ์ฑ๋ฅ ์ธก์ ๊ฒฐ๊ณผ๊ฐ ์ฝ์์ ์ถ๋ ฅ๋๋ค.
์ด๊ฒ์ด aspect์ด๋ฉฐ Spring์ด ์ ๊ณตํด์ฃผ๋ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ AOP์ด๋ค.
์ด๋ ๊ฒ ์ ์ฉํ AOP๋ ๋ด๋ถ์ ์ผ๋ก ํ๋ก์ ํจํด ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ค.
References
์ธํ๋ฐ - ๋ฐฑ๊ธฐ์ ๋์ ์์ ๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ์ ๋ฌธ(๊ฐ์ ํ)
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] ์ ์๋ฐ ๊ฐ์ฒด๋ฅผ IoC ์ปจํ ์ด๋์ ๋น์ผ๋ก ๋ง๋ค๊น? (0) | 2020.03.01 |
---|---|
[Spring] ์คํ๋ง PSA (0) | 2020.03.01 |
[Spring] ์์กด์ฑ ์ฃผ์ (DI, Dependency Injection)์ ์ธ๊ฐ์ง ๋ฐฉ๋ฒ (0) | 2020.02.28 |
[Spring] ์คํ๋ง ๋น(Bean)์ ๊ฐ๋ ๊ณผ ์์ฑ ์๋ฆฌ (6) | 2020.02.28 |
[Spring] ์คํ๋ง ์์ PetClinic ํ๋ก์ ํธ ๋ถ์ ๋ฐ ๊ธฐ๋ฅ ๋ณ๊ฒฝ (0) | 2020.02.28 |
๋๊ธ