본문 바로가기
java/spring

spring - aop

by rewind 2024. 7. 10.

돌아가는 방식은 대충 파악 했으니 이제 라이브러리로 사용해보자 먼저 aop에서 사용하는 용어들 정리

용어 역할
Target Advice가 적용될 객체
Advice Target에 동적으로 추가될 부가기능(코드)
Join Point Advice가 추가(join)될 대상(메서드)
Pointcut Join Point들을 정의한패턴. 예) execution(* com.fastcampus.*.*(..))
Proxy Target에 Advice가 동적으로 추가되어 생성된 객체
Weaving Target에 Advice를 추가해서 Proxy를 생성하는 것

 

아래는 Advice의 종류

종류  애너테이션  설 명
Around Advice  @Around  메서드의 시작과 끝부분에서 실행(메서드 호출 전후 및 예외 발생 시점) → 주로 성능 측정, 트랜잭션 관리, 보안 체크 등에 사용
Before Advice  @Before  메서드의 시작 부분에서 실행(타겟 메서드 실행 전) → 검증, 인증, 인가 검사, 파라미터 유효성 검사 등에 사용(전처리)
After Advice  @After  메서드의 끝 부분에서 실행(타겟 메서드 실행된 후) → 예외발생과 관련없이 실행, 자원 해제, 로깅 등의 후처리 작업
After Returning  @AfterReturning 예외가 발생 하지 않았을 때만(타겟 메서드가 정상적으로 반환된 후에 실행) → 메서드의 반환 값을 가공하거나 추가적인 로깅 등을 수행
After Throwing  @AfterThrowing  예외가 발생 했을 때 실행(타겟 메서드에서 예외가 발생한 후) → 예외 발생 시 로깅 및 예외 처리 등을 수행

 

아래 3가지 라이브러리가 있어야 한다

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${org.aspectj-version}</version>
</dependency>

 

간단한 계산기와 계산할때 시작 전후 로그와 메서드 동작시간을 출력해주는 AOP를 적용해보자

1. 메인기능 담당

2. 부가기능 담당(+AOP 관련 xml 파일)

실행 클래스 총 3개 작성

 

AspectJ 기반 AOP를 자동으로 설정하기 위해 root-context_aop.xml 파일 생성 후 아래 내용을 작성

→ 이 파일은 root-context.xml 에 같이 작성해도 되지만 우선 별도로 분리해서 작성

root-context_aop.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
    <!-- Root Context: defines shared resources visible to all other web components -->
	<aop:aspectj-autoproxy/>
	<context:component-scan base-package="com.fastcampus.ch3.aop" />
</beans>

→ 여기서 aop사용시 <aop:aspectj-autoproxy/>를 작성하게 되는데 가장 윗부분 bean 스키마 목록에 xmlns:aop를 반드시 적어야함..

 

 

메인 기능을 담당할 MyMath 클래스 - @Component 선언(스프링에서 빈 관리)

import org.springframework.stereotype.Component;

@Component		// 스프링 빈객체 등록
public class MyMath {
// 계산기능(핵심기능)
	public int add(int a, int b)		{ return a + b; }
	public int add(int a, int b, int c)	{ return a + b + c; }
	public int sub(int a, int b)		{ return a - b; }
	public int multy(int a, int b)		{ return a * b; }
}

 

부가기능을 담당할 LoggingAdvice 클래스(AOP) 

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component			// 스프링 빈객체 등록
@Aspect				// AOP 클래스 선언
public class LoggingAdvice {
    @Around("execution(* com.fastcampus.ch3.aop.MyMath.add*(..))")
    // AOP를 적용하고자 하는 부분
    // pointcut - 부가기능이 적용될 메서드의 패턴
    // com.fastcampus.ch3.aop.MyMath 클래스의 이름이 add로 시작하는 모든 메서드를 타겟으로 지정
    public Object methodCallLog(ProceedingJoinPoint pjp) throws Throwable {
		long start = System.currentTimeMillis();
		System.out.println("<<[start] " + pjp.getSignature().getName()+ Arrays.toString(pjp.getArgs()));
		Object result = pjp.proceed();  // target의 메서드를 호출
		System.out.println("result="+result);
		System.out.println("[end]>> " + (System.currentTimeMillis() - start) + "ms");
		return result;
    }
}

 

LoggingAdvice 클래스에 @Component, @Aspect 선언하고 처음에 AOP의 용어가 어느 부분에 해당되는지 보면

1. Target : com.fastcampus.ch3.aop.MyMath 클래스의 인스턴스

2. Advice : @Around 애너테이션으로 정의된 메서드(methodCallLog 메서드)

3. JoinPoint : com.fastcampus.ch3.aop.MyMath 클래스의 add로 시작하는 메서드 호출

4. PointCut : "execution(* com.fastcampus.ch3.aop.MyMath.add*(..))" 표현식(add로 시작하는 모든 메서드)

5. Proxy : AOP 프레임워크가 생성한 com.fastcampus.ch3.aop.MyMath 클래스의 프록시 객체

6. Weaving : 런타임에 프록시를 통해 Advice를 적용

 

이걸 실행할 AopMain2 클래스를 만들고 실행

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class AopMain2 {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context_aop.xml");
        MyMath mm = (MyMath)ac.getBean("myMath");
        mm.add(3,5);
        mm.add(1,2,3);
        System.out.println("mm.multy(3,5) = "+mm.multy(3,5));
    }
}

 

잘 실행된다

 

수업때 했던 것들 찾아보면 나올텐데.. 봐서 보충할거 있으면 보충해야겠다