AOP (Aspect Oriented Programming)
?�� ?�습 코드:
com.aop.step1~com.aop.step4
IoC/DI처럼 ?�수 ?�바 ??Spring AOP까�? ?�계?�으�??�습
0. ?�습 ?�름 (Step 1 ??4)
| Step | ?�키지 | ?�심 | ?�행 |
|---|---|---|---|
| Step 1 | com.aop.step1 |
AOP ?�이 - 부가 로직???�심 로직??직접 ?�임 | step1.Main ?�행 |
| Step 2 | com.aop.step2 |
?�록???�턴 - ?�동?�로 부가 로직 분리 | step2.Main ?�행 |
| Step 3 | com.aop.step3 |
JDK Dynamic Proxy - 리플?�션?�로 ?�동 ?�록?? | step3.Main ?�행 |
| Step 4 | com.aop.step4 |
Spring AOP - @Aspect + Pointcut ?�언???�용 | step4.Main ?�행 |
Step1: 모든 메서?�에 로깅 코드 중복 ??"?�거 ?�무 불편?�데?"
Step2: ?�록???�턴?�로 분리 ??"분리?��?�??�록???�래?��? 직접 ?�성?�야 ?�네..."
Step3: Dynamic Proxy�??�동?? ??"?�나??Handler�??�결! 근데 Pointcut??불편..."
Step4: Spring AOP�??�전 ?�동?? ??"?�언�??�면 Spring?????�줌!"
1. AOP?�?
?�심 로직(비즈?�스) �?부가 로직(공통 관?�사) ??분리?�는 ?�로그래�?방식.
부가 로직 ?�시:
- 로깅 (메서???�행 ?�간 측정)
- ?�랜??�� (@Transactional???��??�으�?AOP)
- ?�증/?��? 체크
- ?�외 처리
문제 ?�황
// ??AOP ?�이 - 모든 ?�비?�에 로깅 코드가 중복
public class CommunityService {
public CommunityDTO getCommunityDetail(Long id) {
long start = System.currentTimeMillis();
log.info("getCommunityDetail ?�작");
// ... ?�심 로직
log.info("getCommunityDetail 종료: {}ms", System.currentTimeMillis() - start);
}
}
public class FileService {
public FileEntity getFileById(Long id) {
long start = System.currentTimeMillis();
log.info("getFileById ?�작");
// ... ?�심 로직
log.info("getFileById 종료: {}ms", System.currentTimeMillis() - start);
}
}
AOP�??�결
// ??AOP - 로깅 코드�???곳에�??�성
@Aspect
@Component
@Slf4j
public class LoggingAspect {
// Service 계층??모든 메서?�에 ?�용
@Around("execution(* com.ch.basic..*Service.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
String methodName = joinPoint.getSignature().getName();
log.info("{} ?�작", methodName);
Object result = joinPoint.proceed(); // ?�제 메서???�행
log.info("{} 종료: {}ms", methodName, System.currentTimeMillis() - start);
return result;
}
}
2. ?�심 ?�어
| ?�어 | ?�명 | ?�시 |
|---|---|---|
| Aspect | 부가 로직??모아???�래?? | LoggingAspect |
| Advice | ?�제 부가 로직 (?�제 ?�행?��?) | @Before, @After, @Around |
| Pointcut | ?�디???�용?��? ?�현?? | execution(* *Service.*(..)) |
| JoinPoint | ?�용 가?�한 지?? | 메서???�행 ?�점 |
| Target | 부가 로직???�용?�는 ?�제 객체 | CommunityService |
| Proxy | Target??감싸??AOP 객체 | Spring???�동 ?�성 |
3. Advice 종류
@Aspect
@Component
public class ExampleAspect {
// 메서???�행 ??
@Before("execution(* com.ch.basic..*Service.*(..))")
public void before(JoinPoint joinPoint) {
log.info("메서???�행 ?? {}", joinPoint.getSignature().getName());
}
// 메서???�행 ??(?�외 ?��??�이)
@After("execution(* com.ch.basic..*Service.*(..))")
public void after(JoinPoint joinPoint) {
log.info("메서???�행 ??);
}
// ?�상 반환 ??
@AfterReturning(pointcut = "execution(* com.ch.basic..*Service.*(..))",
returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
log.info("?�상 반환: {}", result);
}
// ?�외 발생 ??
@AfterThrowing(pointcut = "execution(* com.ch.basic..*Service.*(..))",
throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
log.error("?�외 발생: {}", ex.getMessage());
}
// ????모두 ?�어 (가??많이 ?�)
@Around("execution(* com.ch.basic..*Service.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// ?�행 ??
Object result = joinPoint.proceed(); // ?�제 메서???�행
// ?�행 ??
return result;
}
}
4. Pointcut ?�현??
execution(?�근?�어??반환?�???�키지.?�래??메서???�라미터))
execution(* com.ch.basic..*Service.*(..))
?? ?? ????
모든 반환 ..(?�위 ?�키지 ?�함) 모든 메서?? 모든 ?�라미터
| ?�턴 | ?�명 |
|---|---|
* |
모든 �? |
.. |
0�??�상???�키지/?�라미터 |
execution(* *..*Service.*(..)) |
?�름??Service�??�나??모든 ?�래?�의 모든 메서?? |
@annotation(Transactional) |
@Transactional 붙�? 메서?? |
5. ?�무 ?�용 ?�시
// ?�행 ?�간 측정
@Around("execution(* com.ch.basic..*Service.*(..))")
public Object logTime(ProceedingJoinPoint pjp) throws Throwable { ... }
// 로그??체크 (Interceptor?� ?�사)
@Before("execution(* com.ch.basic..*.write(..))")
public void checkLogin(JoinPoint jp) { ... }
// ?�라미터 로깅
@Before("execution(* com.ch.basic..*Controller.*(..))")
public void logRequest(JoinPoint jp) {
log.info("?�청: {} - ?�라미터: {}", jp.getSignature(), jp.getArgs());
}
6. @Transactional??AOP??
CommunityService.createCommunity() ?�출
??
?�제로는 Spring??만든 Proxy 객체가 먼�? 받음
??
Proxy: ?�랜??�� ?�작
??
?�제 CommunityService.createCommunity() ?�행
??
Proxy: ?�공 ??커밋 / ?�외 ??롤백
7. ?�습 코드 ?�세 (Step 1 ??4)
Step 1: AOP ?�이 (com.aop.step1)
?�일 구조:
step1/
?��??� Main.java ???�행
?��??� OrderService.java ???�심 로직 + 부가 로직 ?�여?�음
?��??� OrderRepository.java ???�이???�근
*?�심 ?�인??: OrderService??모든 메서?�에 로깅/?�간측정 코드가 중복??
// ??모든 메서?�에 같�? 코드가 반복!
public String getOrder(Long id) {
long start = System.currentTimeMillis(); // 중복
System.out.println("[LOG] getOrder() ?�작"); // 중복
String result = orderRepository.findById(id); // ???�심 로직?� ?�것�?
long end = System.currentTimeMillis(); // 중복
System.out.println("[LOG] getOrder() 종료"); // 중복
return result;
}
Step 2: ?�록???�턴 (com.aop.step2)
?�일 구조:
step2/
?��??� Main.java ???�행
?��??� OrderService.java ???�터?�이??(?�록???�턴???�심)
?��??� OrderServiceImpl.java ???�심 로직�? (부가 로직 ?�음)
?��??� OrderServiceProxy.java ????부가 로직???�당?�는 ?�록??
?��??� OrderRepository.java ???�이???�근
*?�심 ?�인??: 부가 로직??Proxy�?분리, ?�심 로직?� 깨끗?�짐
Client ??OrderServiceProxy(부가 로직) ??OrderServiceImpl(?�심 로직)
// ???�록?��? 부가 로직???�당
public class OrderServiceProxy implements OrderService {
private final OrderService target; // ?�제 객체
public String getOrder(Long id) {
// 부가 로직
String result = target.getOrder(id); // ?�심 로직 ?�임
// 부가 로직
return result;
}
}
?��? 문제: 메서?�마???�록??코드 ?�성, Service마다 Proxy ?�래???�요
Step 3: JDK Dynamic Proxy (com.aop.step3)
?�일 구조:
step3/
?��??� Main.java ???�행
?��??� OrderService.java ???�터?�이??
?��??� OrderServiceImpl.java ???�심 로직
?��??� PaymentService.java ????번째 ?�터?�이??(?�사?�성 증명)
?��??� PaymentServiceImpl.java ???�심 로직
?��??� LoggingHandler.java ????InvocationHandler (?�나�?모든 Service???�용!)
?��??� OrderRepository.java ???�이???�근
*?�심 ?�인??: ?�나??LoggingHandler�??�떤 ?�터?�이?�든 ?�록???�동 ?�성
// ??모든 메서???�출?????�나??메서?�로 ?�어??
public class LoggingHandler implements InvocationHandler {
private final Object target;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 부가 로직 (?�행 ??
Object result = method.invoke(target, args); // = Spring??proceed()
// 부가 로직 (?�행 ??
return result;
}
}
// ?�용: Proxy.newProxyInstance()�??�적 ?�록???�성
OrderService proxy = (OrderService) Proxy.newProxyInstance(
OrderService.class.getClassLoader(),
new Class[]{OrderService.class},
new LoggingHandler(realService)
);
?��? 문제: ?�터?�이???�수, Pointcut(?�떤 메서?�에 ?�용?��?) 지??불편
Step 4: Spring AOP (com.aop.step4)
?�일 구조:
step4/
?��??� Main.java ???�행 (Spring 컨테?�너 ?�용)
?��??� AopConfig.java ??@Configuration + @EnableAspectJAutoProxy
?��??� LoggingAspect.java ????@Aspect - 부가 로직 (?�언??)
?��??� OrderService.java ???�터?�이??
?��??� OrderServiceImpl.java ??@Service - ?�심 로직
?��??� PaymentService.java ???�터?�이??
?��??� PaymentServiceImpl.java ??@Service - ?�심 로직
?��??� OrderRepository.java ???�이???�근
*?�심 ?�인??: @Aspect + Pointcut?�로 ?�언??AOP, Spring???�록???�동 ?�성
@Aspect
@Component
public class LoggingAspect {
// Pointcut?�로 ?�용 ?�?�을 ?�확??지??
@Around("execution(* com.aop.step4.*ServiceImpl.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
// 부가 로직 (?�행 ??
Object result = joinPoint.proceed(); // = Step3??method.invoke()
// 부가 로직 (?�행 ??
return result;
}
}
8. ?�체 비교 ?�리
?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step ?? 방식 ?? ?�징 ??
?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step 1 ?? AOP ?�음 ?? 부가 로직 직접 ?�성 (중복) ??
?? Step 2 ?? ?�록???�턴 (?�동) ?? 분리 ?�공, ?�록??직접 ?�성 ??
?? Step 3 ?? JDK Dynamic Proxy ?? ?�동 ?�록?? ?�터?�이???�수??
?? Step 4 ?? Spring AOP (@Aspect) ?? ?�언?? Pointcut, ?�동 ?�록?�│
?��??�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Step3 (Dynamic Proxy) ?? Step4 (Spring AOP) ??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??
?? Proxy.newProxyInstance() ?? Spring???�동 ?�성 ??
?? InvocationHandler.invoke() ?? @Around 메서?? ??
?? method.invoke(target, args) ?? joinPoint.proceed() ??
?? 모든 메서??무조�??�용 ?? Pointcut?�로 ?�택 ?�용 ??
?? ?�터?�이???�수 ?? ?�래?�만 ?�어??OK (CGLIB) ??
?��??�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�??