스프링의 AOP는 AspectJ의 문법을 차용하며, AspectJ가 제공하는 기능 일부만 제공
횡단 관심사의 깔끔한 모듈화
오류 검사 및 처리
동기화
성능 최적화 (캐싱)
모니터링 및 로깅
AspectJ 에서 AOP 적용 방식
컴파일 시점
클래스 로딩 시점
런타임 시점(프록시) → 스프링에서 사용하는 방식
Spring AOP 관련 용어들 다시 정리
Join Point
"어디서 AOP를 적용할 수 있지?" Spring AOP 기준: public 메서드 호출 시점 (즉, 메서드 실행 전후 등)
Pointcut
Advice 적용할 Join Point(메서드)들을 패턴으로 골라내는 규칙 Join Point들 중 실제로 Advice가 적용될 타깃을 골라내는 규칙 예: "com.example.service 패키지 아래의 모든 메서드"
Target
어드바이스를 받는 객체 핵심 비즈니스 로직이 구현된 클래스
Advice
부가 기능 특정 조인포인트에서 Aspect에 의해 취해지는 조치 Around, Before, After 와 같은 다양한 종류의 어드바이스가 있음
Aspect
"공통 관심사"의 덩어리. 어드바이스+포인트컷을 모듈화 한 것 @Aspect
Weaving
Advice를 실제 Target Object 코드에 붙이는 과정 Spring AOP는 런타임에 프록시(Proxy) 객체를 만들어 위빙함
Proxy
Advice가 주입된, Target Object를 감싸는 대리 객체 실제 Service 객체 대신 프록시를 Bean으로 주입해서 AOP 적용
자동 프록시 생성기가 하는 일
@Aspect를 보고 Advisor로 변화 후 저장
Advisor를 기반으로 프록시 생성
1.@Aspect를 Advisor로 변환 후 저장
스프링 애플리케이션 로딩 시점에 자동 프록시 생성기를 호출
자동 프록시 생성기는 스프링 컨테이너에서 @Aspect 어노테이션이 붙은 스프링 빈 모두 조회
@Aspect 어드바이저 빌더를 통해 @Aspect 애노테이션 정보를 기반으로 어드바이저 생성
생성한 어드바이저를 @Aspect 어드바이저 빌더 내부 저장
*참고
@Aspect 어드바이저 빌더
BeanFactoryAspectAdvisorBuilder 클래스
Aspect 의 정보를 기반으로 포인트컷 , 어드바이스 , 어드바이저를 생성보관
2. Advisor를 기반으로 프록시 생성
1.스프링 빈 대상이 되는 객체 생성 (@Bean , 컴포넌트 스캔)
2.전달된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달(PostBeanProcessor??)
3-1. 스프링 컨테이너에서 Advisor 빈을 모두 조회
3-2. @Aspect 어드바이저 빌더 내부에 저장된 Advisor 를 모두 조회 4. 앞서 3-1, 3-2에서 조회한 Advisor 에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다. 이때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트컷에 하나하나 모두 매칭해본다. 그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다. 예를 들어서 메서드 하나만 포인트컷 조건에 만족해도 프록시 적용 대상이 된다. 5. 프록시 적용 대상이면 프록시를 생성하고 프록시를 반환한다. 그래서 프록시를 스프링 빈으로 등록한다. 만약 프록시 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링 빈으로 등록한다. 6. 반환된 객체는 스프링 빈으로 등록된다.
@Bean
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("Scheduler-Thread-");
scheduler.initialize();
return scheduler;
}
4.2 TimerManagerTaskScheduler
참고) 유연한 조건을 이용!할때 쓰는 Trigger 인터페이스
package org.springframework.scheduling;
import java.util.Date;
import org.springframework.lang.Nullable;
public interface Trigger {
@Nullable
Date nextExecutionTime(TriggerContext var1);
}
그 Trigger 인터페이스를 구현한 CronTrigger CronExpression을 지원한다.
package org.springframework.scheduling.support;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
public class CronTrigger implements Trigger {
private final CronSequenceGenerator sequenceGenerator;
public CronTrigger(String expression) {
this.sequenceGenerator = new CronSequenceGenerator(expression);
}
public CronTrigger(String expression, TimeZone timeZone) {
this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
}
public String getExpression() {
return this.sequenceGenerator.getExpression();
}
public Date nextExecutionTime(TriggerContext triggerContext) {
Date date = triggerContext.lastCompletionTime();
if (date != null) {
Date scheduled = triggerContext.lastScheduledExecutionTime();
if (scheduled != null && date.before(scheduled)) {
date = scheduled;
}
} else {
date = new Date();
}
return this.sequenceGenerator.next(date);
}
public boolean equals(Object other) {
return this == other || other instanceof CronTrigger && this.sequenceGenerator.equals(((CronTrigger)other).sequenceGenerator);
}
public int hashCode() {
return this.sequenceGenerator.hashCode();
}
public String toString() {
return this.sequenceGenerator.toString();
}
}
5. Annotaion 활용 ( @Scheduled , @Async )
5.1 @Scheduled
태스크 역할을 맡은 메소드에 직접 스케줄 정보를 어노테이션을 통해 부여해 수케줄이 적용되게 해준다.
@Scheduled 부여되는 메소드는 파라미터를 가질 수 없으며 반드시 void형 리턴 타입이어야한다.
- fixedDelay : 이전 작업이 끝난 시점부터 일정시간이 지난후에 동작하도록 설정 ,
이전 작업이 끝난후로 부터 정해진 시간이 지난후 다음작업이 시작된다.
@Schduled (fixedDelay=60000)
public void testFixedDelay(){...}
- fixedRate : 밀리초로 설정된 일정한 시간간격으로 메소드 실행
@Schduled (fixedRate=60000)
public void testFixedRate(){...}