Spring AOP

✒️ 2025-05-28 11:41 내용 수정


Aspect-Oriented Programming

용어 설명
Aspect 여러 클래스를 가로지르는 관심 사항의 모듈화, Advice + Pointcut
Spring AOP에선 Aspect를 일반 클래스로 구현하거나, 일반 클래스에 @Aspect Annotation을 추가하여 구현함
Join point 프로그램 실행 지점(ex: 예외를 담당하는 메소드의 실행)을 의미하며, Spring에서는 항상 메소드 실행 지점을 의미함
Advice 특정 Join point에서 Aspect에 의해 실행되는 액션으로, 반복 로직의 구현체
around : 메소드 실행 전 후
before : 메소드 실행 전
after : 메소드 실행 후
AfterReturning : 메소드가 반환값을 반환한 후
AfterThrowing : 메소드가 예외처리를 한 후
Pointcut Join point보다 더 세분화된 지점을 의미함(ex: 특정 이름일 때 메소드 실행)
Introduction 추가적인 메소드나 필드를 타입에 선언하는 것
Target object 한 개 이상의 Aspect에 의해 조언을 받는 객체
AOP proxy AOP 프레임워크에 의해 Aspect 조건을 구현하기 위한 객체
Weaving 다른 어플리케이션과 연결된 Aspect나 advise 객체를 생성하기 위한 객체

Spring에서 AOP 만들기

Annotation 설명
@Aspect Aspect 클래스를 선언할때 사용하는 Annotation
@Pointcut(execution()) pointcut을 지정하는 Annotation. execution()를 사용해서 특정 메소드 실행 지점을 설정할 수 있음
@Before("메소드이름") 특정 메소드 실행 전에 수행할 Advice(액션)을 설정
@After("메소드이름") 특정 메소드 실행 후에 수행할 Advice(액션)을 설정
@EnableAspectJAutoProxy AspectJ 스타일의 선언적 Aspect를 지원하도록 활성화하는 Annotation
AspectJ 스타일의 AOP를 활성화 하면 스프링은 @Aspect Annotation을 가진 클래스를 찾아서 프록시를 생성하고, 해당 Aspect를 적용
  1. Annotation 기반 설정 파일#프로젝트 설정, 방명록 만들기대로 파일들 및 패키지를 준비한다.
  2. https://mvnrepository.com/artifact/org.aspectj/aspectjweaver 에 접속해서 현재 pom.xml에서 properties에 있는 org.aspectj-version의 버전과 동일한 버전의 Maven 항목을 복사해 dependencies에 추가한다. (1.9.0버전 사용)
	<properties>
		<java-version>11</java-version>
		<org.springframework-version>5.1.20.RELEASE</org.springframework-version>
		<!-- 이 항목의 버전과 동일한 버전으로 받는다 -->
		<org.aspectj-version>1.9.0</org.aspectj-version> 
		<org.slf4j-version>1.7.25</org.slf4j-version>
	</properties>
<!-- aspectjweaver -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.0</version>
</dependency>

aop 1.png

  1. src/main/resources 폴더에 advice 패키지를 만들고 Advice 클래스를 만든다.
package advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect//Aspect 클래스를 선언할때 사용하는 어노테이션
public class Advice {

	long start;
	
	//execution() : 메서드 실행을 나타내는 키워드
	//* : 반환타입
	//dao.*DAO : dao패키지의 DAO로 끝나는 모든 클래스
	//.* : 모든 메서드
	//(..) : 메서드의 매개변수의 개수는 상관없음
	@Pointcut("execution(* dao.*DAO.*(..))")
	public void myPoint() {};
	
	@Before("myPoint()")
	public void before(JoinPoint jp) { //JoinPoint : pointcut이 걸린 위치의 정보를 받는 클래스
		System.out.println("----before : " + jp.getSignature());
		//getSignature() : 현재 JoinPoint에서 실행되는 메서드의 서명정보 반환
		//서명정보에는 메서드명, 반환형, 파라미터 타입 등등이 존재
		
		start = System.currentTimeMillis();
		
	}
	
	@After("myPoint()")
	public void after(JoinPoint jp) {
		System.out.println("----after: " + jp.toLongString());
		
		long end = System.currentTimeMillis();
		
		System.out.printf("[수행시간] : %d(ms)\n",end-start);
	}
	
}
  1. src/main/resources 폴더에 dao 패키지를 만들어 TestDAO 클래스를 만든다.
    • test() 메소드의 수행 시간을 Advice에서 캐치하려는데, 메소드 1개를 호출하는 시간은 0초에 가깝기 때문에 임의로 시간 딜레이를 준다.
package dao;

public class TestDAO {

	public void test() {
		System.out.println("---- call TestDAO.test() ----");
		try {
			Thread.sleep(3000); // 3초 대기를 걸어준다.
		} catch (Exception e) {
		}
	}
}
  1. Context_3_dao 클래스에 객체를 생성한다.
    • AspectJ 스타일의 AOP를 활성화 하면 스프링은 @Aspect 어노테이션을 가진 클래스를 찾아서 프록시를 생성하고, 해당 Aspect를 적용한다.
package context;

import org.apache.ibatis.session.SqlSession;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import advice.Advice;
import dao.TestDAO;

@Configuration
@EnableAspectJAutoProxy
public class Context_3_dao {

	@Bean
	public TestDAO testDAO() {
		return new TestDAO();
	}
	
	@Bean
	public Advice advice() {
		return new Advice();
	}
}
  1. 프로젝트를 실행하고 console 창을 보면 메소드 수행 시간이 Thread로 딜레이를 줬던 거의 3초가 나온다.

aop 2.png