스프링 AOP (스프링 핵심 기술 - 5)
1. AOP (Aspect-Oriented Programming) 이란?
- OOP를 보완하는 수단으로, 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법
- 흩어진 관심사들을 하나로 모아서 Aspect로 모듈화하는 기법
2. 주요 개념
- Aspect : 모듈
- Target : 적용되는 대상 (Class A, B)
- Advice : 해야할 일
- Join Point : 합류 지점 (생성자 호출 전, 메소드를 호출하기 전, 필드에서 값을 가져갈 때...)
- Pointcut : 어디에 적용되어야 하는지
3. 구현체
- AspectJ (다양한 Join Point를 사용해야 할 때)
- 스프링 AOP
- 둘을 연동해서 사용 가능
3. 적용 방법
- 컴파일 타임 : 컴파일 할 때, 조작된 자바 바이트 코드를 생성 (AspectJ 컴파일러)
- 로드 타임 : 바이트 코드를 로드할 때 생성 (AspectJ 사용)
- 런타임 : A객체 빈을 만들 때, 이를 감싸는 proxy 빈을 만듬 (스프링 AOP 사용 - 합리적이고, 자주 쓰게될 방법)
4. 스프링AOP
- 프록시 기반의 AOP 구현체
- 스프링 빈에만 AOP를 적용할 수 있다
프록시 패턴
- 왜 프록시 패턴 사용? 기존 코드 변경 없이 접근 제어 또는 부가 기능 추가
- Proxy는 RealSubject를 참조하며 이 기능 + 추가적인 기능을 수행함.
- Client와 RealSubject 코드의 변경없이 기능 추가
- 매번 프록시 클래스 생성, 객체들 관계 복잡 등 문제 있음 따라서 스프링 AOP 등장
스프링AOP
- 스프링 IoC컨테이너가 제공하는 기반 시설과 Dynamic 프록시를 사용하여 복잡한 문제 해결
- 동적 프록시 (동적으로 프록시 객체를 생성)
- 스프링 IoC의 AbstractAutoProxyCreator(BeanPostConstruct를 상속)는 기존 빈을 대체하는 동적 프록시 빈을 만들 어 등록 시켜줌
5. @AOP
- 어노테이션 기반의 @AOP
1. 의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. Aspect 정의
@Component
@Aspect
public class PerfAspect {
// 어디에 적용할 것인가 (포인트 컷)
@Around("@annotation(PerfLogging)")
// 해야할 일 (어드바이스)
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
// pjp 는 적용되는 부분으로 (메소드 그 자체)
long begin = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - begin);
return retVal;
}
@Before("bean(simpleEventService)")
public void printHello(){
System.out.println("Hello~");
}
}
3. 어노테이션 정의
/*
이 어노테이션을 사용하면 성능을 측정해줍니다.
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerfLogging {
}
참고)
// 인터페이스 타입인 경우 인터페이스로 주입 받는 것을 권장함
@Autowired
EventService eventService;
/*
실무에서 우려되는 부분은
인터페이스를 쓰지 않을 때 다음과 같은 복잡한 문제가 생길 수 있음
인터페이스를 기반으로 프록시 객체를 만들도록 설정하면
MyService -> DefaultMyService
MyService -> ProxyService
ProxyService 는 DefaultMyService 와 상속관계가 아니므로 불러올 수 없음
스프링 부트는 default로 클래스를 기반으로 프록시 객체를 만듬
MyService -> DefaultMyService -> ProxyService
*/
// 이렇게 같은 타입으로 지정하거나, 같은 클래스 이름으로 지정하면 해당 빈을 주입받을 수 있음
@Autowired
SimpleEventService simpleEventService;
@Autowired
EventService simpleEventService;
인프런 백기선님 '스프링 프레임워크 핵심 기술' 강의를 듣고 정리한 내용입니다.