geeone 스터디 블로그
[Spring] GDG 4주차 WIL : 관점 지향 프로그래밍(AoP) 및 커스텀 어노테이션 본문
스프링 세션 4주차 내용 복습
1. 관점 지향 프로그래밍(AOP)
Overview
애플리케이션에는 부가 기능과 핵심 기능이 있는데, 부가 기능이 중복되어 코드 전반에 흩어져 있다면 AOP(핵심 기능과 부가 기능을 분리) 를 바탕으로 부가 기능과 적용할 위치를 합쳐 Aspect라는 객체로 모듈화하면 된다.


AOP란?
횡단 관심사를 핵심 비즈니스 로직에서 분리하여 모듈성을 향상시키는 프로그래밍 패러다임
AOP에서는 횡단 괌심사(부가기능)를 Asepct라는 특별한 객체로 모듈화한다. Asepct 객체에는 무엇을 언제 어디서 할 지에 대한 정보가 모두 정의되어 있다.
AOP 용어
1. Asepct
- 부가 기능을 모듈화한 것
- Advice(What&When) + Pointcut(Where)
2. Target
- Aspect가 적용될 객체
- e.g. 클래스, 메소드
3. Advice
- Aspect가 특정 JoinPoint에서 해야 하는 부가 기능(What&When)
- types : before, after, after-returning, after-throwing, around
4. JointPoint
- Advice가 적용될 수 있는 지점
- e.g. 메서드 진입 시점/생성자 호출 시점 등...
- Spring AOP에서는 항상 메서드 진입 시점
5. Pointcut
- 어떤 JoinPoint에 Advice를 적용할 지 결정하는 기준
- e.g. 클래스 이름/메서드 이름/ 파라미터 등...
6. Weaving
- Pointcut에 의해 결정된 Target의 JoinPoint에 Advice를 삽입하는 과정
- types : 컴파일 타임, 클래스 로드 타임, 런타임 위빙
- Spring AOP에서는 런타임 위빙만 사용

스프링 AOP
- @AspectJ 방식 또는 XML 방식으로 구현 가능

- 스프링 AOP는 프록시를 기반으로 설계되었다. (스프링은 기존의 코드를 수정하지 않고, 추가적인 동작을 더하기 위해 프록시를 사용한다.)
프록시
프록시 객체는 원래 객체를 감싸고 있는 객체이다. 기존 객체의 인터페이스를 유지하고 추가적인 동작을 수행한다. 접근을 제어하

고 싶거나, 부가 기능을 추가하고 싶을 때 사용한다.
클라이언트가 객체를 사용할 때, 스프링 컨테이너는 대상 객체 대상 객체(Target)를 감싼 프록시 객체를 제공한다.
핵심 비즈니스 로직을 감싼 프록시가 부가 기능을 수행하여, 기존 코드를 수정하지 않고도 부가 기능을 추가할 수 있다. 이를 통해 핵심 로직과 부가 기능을 분리할 수 있다. 프록시는 Target 객체에 대한 호출을 가로채(Intercept) Advice의 부가기능을 수행한 후 Target의 핵심 기능을 호출한다.
Aspect 우선순위
동일한 JoinPoint에 여러 개의 Advice가 적용된다면, 원하는 순서대로 수행되지 않을 수 있다. 따라서, Aspect들의 순서를 지정해주어야 한다. 우선순위가 높을수록 (숫자가 작을수록) 바깥의 프록시 객체이다.

@Order 어노테이션
@Aspect
@Order(1)
@Component
public class MyAspect1 {
// Executes first }
@Aspect
@Order(2)
@Component
public class MyAspect2 {
// Executes later
}
Ordered 인터페이스
import org.springframework.core.Ordered;
@Aspect
@Component
public class MyAspect1 implements Ordered {
@Override
public int getOrder() {
return 1;
}
// Executes first }
@Aspect
@Component
public class MyAspect2 implements Ordered {
@Override
public int getOrder() {
return 2;
}
// Executes later
}
2. 커스텀 어노테이션
어노테이션
코드 사이에 주석처럼 쓰이면서 특별한 의미, 기능을 수행하도록 하는 기술을 말한다.
프로그램에 추가적인 정보를 제공해주는 메타데이터이다.
어노테이션의 용도
1. 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공한다.
2. 소프트웨어 개발툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보를 제공한다.
3. 런타임 시 특정 기능을 실행하도록 정보를 제공한다.
-> Spring에서 제공되는 대부분의 어노테이션은 3번, 런타임 시 특정 기능을 실행하도록 정보를 제공하는 용도로 사용되고 있다.
커스텀 어노테이션
1. @interface 타입으로 정의
2. 메타 어노테이션 추가
- 메타 어노테이션 : 다른 어노테이션에 적용되기 위한 어노테이션
@Target

ElementType.PACKAGE : 패키지 선언
ElementType.TYPE : 타입 선언
ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
ElementType.CONSTRUCTOR : 생성자 선언
ElementType.FIELD : 멤버 변수 선언
ElementType.LOCAL_VARIABLE : 지역 변수 선언
ElementType.METHOD : 메서드 선언
ElementType.PARAMETER : 전달인자 선언
ElementType.TYPE_PARAMETER : 전달인자 타입 선언
ElementType.TYPE_USE : 타입 선언
@Retention
어노테이션 보존 범위

RetentionPolicy.SOURCE : 컴파일 전까지만 유효
RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효
RetentionPolicy.RUNTIME : 컴파일 이후 런타임 시기에도 JVM에 의해 참조가 가능
@Documented
: Javadoc 포함 여부
@Inherited
: 자식에게 어노테이션 상속 여부
커스텀 어노테이션 기반 AOP
1. app dependency 추가 (build.gradle/pom.xml)
2. 커스텀 어노테이션 작성
3. aspect 생성(@Aspect)
4. Pointcut, Advice 생성
5. 실행
4주차 과제
커스텀 어노테이션과 AOP를 활용한 성능 모니터링 관점 구현.
특정 메소드가 성능 모니터링을 위한 메소드임을 커스텀 어노테이션으로 명시해주세요. 성능 모니터링은 실행시간 로깅(시간복잡도)이 되어도 좋고, 메모리 차지 비율 등이 되어도 좋습니다. 필요한 경우 속성을 작성해주세요 AOP(Aspect-Oriented Programming)는 메소드 실행 전후에 공통적으로 적용할 로직을 분리하여 재사용성을 높이는 기법입니다. 성능 모니터링을 위한 AOP 클래스를 작성해주세요 정의한 커스텀 어노테이션을 성능 모니터링이 필요한 함수에 추가해주세요 시간을 측정해보고싶은 알고리즘이 있다면 그걸 추가해줘도 좋습니다.
메소드를 호출하고 실행한 뒤 결과를 캡처해주세요
PerformanceMonitor.java
package AOPexample;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PerformanceMonitor {
// 필요한 속성을 정의할 수 있습니다.
}
PerformanceAspect.java
package AOPexample;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@EnableAspectJAutoProxy
@Aspect
@Component
public class PerformanceAspect {
@Around("@annotation(PerformanceMonitor)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return result;
}
}
AOPexampleApplication
package AOPexample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@EnableAspectJAutoProxy
public class AOPexampleApplication {
public static void main(String[] args) {
SpringApplication.run(AOPexampleApplication.class, args);
}
}
트러블 슈팅
-> @Aspect 가 인식되지 않았다
1. dependencies 에 "implementation 'org.springframework.boot:spring-boot-starter-aop"를 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
2. 캐시 비우고 재실행
https://ottl-seo.tistory.com/44
IntelliJ `Cannot resolve symbol` 에러 해결 방법 총정리
잘만 돌아가던 프로젝트에 온갖 빨간 줄이 그어졌다. 에러 내용은 "Cannot resolve symbol.. " 사실 이 에러는 IntelliJ IDEA에서 잊을 만 하면 나오는,, 그만큼 자주 보이는 에러이다. 다시 말해 아래와 같
ottl-seo.tistory.com
실행 결과

'Spring' 카테고리의 다른 글
| [Spring] GDG 6주차 WIL : 스프링 DAO와 JDBC 템플릿 및 트랜잭션 관리 (0) | 2024.11.23 |
|---|---|
| [Spring] 강의 스터디 WIL 4주차 (0) | 2024.11.03 |
| [Spring] 강의 스터디 WIL 3주차 (4) | 2024.10.06 |
| [Spring] GDG 3주차 WIL (0) | 2024.10.04 |
| [Spring] GDG 2주차 WIL (2) | 2024.09.27 |