티스토리 뷰
인프런에서 '백기선의 스프링 프레임워크 핵심기술' 이라는 강의를 꾸준히(?) 수강하고 있다.
오늘은 AOP에 대한 강의를 들었고, 정의하려고 한다. 이전에 AOP 관련되서 글을 정리한적이 있는데, 다시 봤는데! 나름 괜찮다!
- Compile-Time Weaving
- 바이트 코드를 만드는 과정에서 Aspect를 추가하는 방식
- 빠른 실행 속도
- 복잡한 설정
- 컴파일 시에 영향을 주는 plugin (예 : Lombok) 과 충돌 가능
- Run- Time Weaving
- Bean 객체에 Aspect를 추가하는 방식
- 바이트 코드를 변경하지 않기 때문에 플러그인과 충돌 가능성이 없음
- 스프링의 기본설정이기 때문에 쉬운 설정
- 스프링 AOP 같은 경우, 제한적인 기능만을 제공 (예 : 메소드를 실행하기 전, 후의 JoinPoint 적용 가능)
- Load-Time Weaving
- 클래스 로딩시 Aspect를 추가하는 방식
- 바이트 코드를 변경하지 않기 때문에 플러그인과 충돌 가능성이 없음
- Java의 Aspect J를 사용하기 때문에 많은 기능 제공
- 복잡한 설정
그러면, AOP를 프록시 패턴을 이용해서 직접 구현을 해보겠다. 위에 글을 보았다면, 프록시 패턴을 이해할 수 있을 것이지만, 그림은 아래와 같다.
package spring.aop.service.aop;
public interface PengsooService {
void pengHi() throws InterruptedException;
void pengBye();
}
package spring.aop.service.aop;
import org.springframework.stereotype.Service;
@Service
public class PengsooServiceImpl implements PengsooService {
@Override
public void pengHi() throws InterruptedException {
Thread.sleep(2000);
System.out.println("PENG HI");
}
@Override
public void pengBye() {
System.out.println("PENG BYE");
}
}
package spring.aop.service.aop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Primary
@Service
public class PengSooProxy implements PengsooService {
@Autowired
private PengsooService pengsooService;
@Override
public void pengHi() throws InterruptedException {
long begin = System.currentTimeMillis();
pengsooService.pengHi();
long finish = System.currentTimeMillis();
System.out.println("time : " + (finish - begin));
}
@Override
public void pengBye() {
pengsooService.pengBye();
}
}
코드와 그림을 매칭하게 되면, 아래와 같다.
PengsooService : Subject Interface
PengSooServiceImpl : Real Subject Class
PengSooProxy : Proxy
이 코드에서 가장 중요한 것은 @Primary 어노테이션이 존재하기 때문에 Autowired 를 할 경우, 프록시가 주입이 된다는 사실이다.
하지만, 지금과 같이 AOP를 구현하게 되면 항상 프록시 객체를 생성해야 한다는 불편함이 존재할 것이고, 중복코드가 많다는 단점도 있다.
그래서 조금더 쉽게 사용할 수 있도록 스프링에서 지원하는 기능이 있다. 그것은 아래와 같다!
@Component
@Aspect
public class PengsooAspect {
// @Around("execution(* spring.aop.service.aop.PengsooService.*(..))") // 기존 코드 수정(X), 중복 (X), 복잡한 설정, 예외처리 불가
@Around("@annotation(Perflogging)") // 기존 코드 수정 (O), 중복 (X), 예외처리 가능
public Object logPerf(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long begin = System.currentTimeMillis();
Object retVal = proceedingJoinPoint.proceed();
long finish = System.currentTimeMillis();
System.out.println("TIME : " + (finish - begin));
return retVal;
}
}
package spring.aop.service.pattern;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.CLASS) // 어노테이션 정보 보관 관련 설정
@Target(ElementType.METHOD)
public @interface Perflogging {
}
위와 같이 스프링에서 제공하는 AOP를 활용하게 되면 굉장히 간단하게 구현할 수 있다느 장점을 가지고 있다.
그리고 기존 코드에 대한 수정없이 적용할 수 있다는 것이 가장 큰 장점이다. 위에 코드를 보면 JoinPoint를 적용할 때, execution 또는 annotation을 이용할 수 있다. 각각 장단점이 있다. execution 같은 경우에는 비즈니스 로직에 어떤 수정도 하지 않아도 된다. (어노테이션을 추가하거나 기타 등등)
그리고, 프록시 객체를 직접 생성하는 경우와 달리 중복코드가 전혀 없다! 하지만, 예외처리가 불가능하다는 단점을 가지고 있다.
그리고 annotaion을 이용할 경우에는 굉장히 설정이 간단하고, 적용 대상에 대한 예외처리가 쉽다는 장점을 가지고 있다. 개인적으로 이 방법을 선호한다.
그러나, 기존 비즈니스 로직에 어노테이션을 추가해야 한다는 코드 수정이라는 단점을 가지고 있다.
오늘은 AOP에 대해 정리를 해봤는데, 아래 github를 들어가면 상세코드를 볼 수 있다!
'인프런 > SpringFramework technology' 카테고리의 다른 글
[인프런] 1. 스프링 ioc 컨테이너와 빈 - 1 (0) | 2020.06.28 |
---|