
public class StudentService {
private final IdentityStudentRepository identityStudentRepository;
private final SequenceStudentRepository sequenceStudentRepository;
private int insertNum = 1000;
public void saveIdentity() {
for (int i = 0; i < insertNum; i++) {
System.out.println("save I: " + i);
identityStudentRepository.save(IdentityStudent.builder()
.num(i)
.build());
}
}
public void saveSequence() {
for (int i = 0; i < insertNum; i++) {
System.out.println("save I: " + i);
SequenceStudent save = sequenceStudentRepository.save(SequenceStudent.builder()
.num(i)
.build());
System.out.println("save id: " + save.getId());
}
}
}



스프링 AOP를 적용할 때, 커스텀 어노테이션을 사용하면 특정 메서드에 유연하게 AOP를 적용할 수 있습니다.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeTrace {
}
### Aspect 클래스 구현
```java
@Log4j2
@Component
@Aspect
public class TimeTraceAspect {
// Pointcut: AOP를 적용할 범위 설정
@Pointcut("@annotation(com.example.Aop.TimeTrace)")
private void timeTracePointcut() {
}
// Around Advice: 실행 전후로 부가기능 실행
@Around("timeTracePointcut()")
public Object traceTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
try {
stopWatch.start();
return joinPoint.proceed(); // 실제 타깃 메서드 호출
} finally {
stopWatch.stop();
log.debug("{} - Total time = {}s",
joinPoint.getSignature().toShortString(),
stopWatch.getTotalTimeSeconds());
}
}
}
@TimeTrace: AOP가 적용될 메서드에 붙이는 커스텀 어노테이션.
@Target: 어노테이션이 적용될 대상(여기서는 메서드).@Retention: 어노테이션 유지 시점(런타임).TimeTraceAspect: AOP 로직을 구현하는 클래스.
@Pointcut: AOP를 적용할 범위를 정의합니다. 위에서는 @TimeTrace 어노테이션이 붙은 메서드만 적용됩니다.@Around: Advice의 일종으로, 메서드 실행 전후에 부가기능을 실행합니다.ProceedingJoinPoint: AOP 대상 메서드 호출 컨텍스트로, 실제 메서드를 호출하기 위해 사용됩니다.