221013 스프링 AOP

Jongleee·2022년 10월 13일
1

TIL

목록 보기
78/576

스프링 AOP

⇒ 공통 모듈을 프록시로 만들어서 DI 로 연결된 빈 사이에 적용해 Target의 메소드 호출 과정에 참여애 부가기능(공통 모듈)을 제공해준다.
그렇기의 JDK 와 Spring Container 외에 특별한 기술 및환경을 요구하지 않는다.
Advice 가 구현하는 MethodInterceptor 인터페이스는 다이내믹 프록시의 InvocationHandler와 마찬가지로 프록시부터 메소드 요청정보를 전달받아 타깃 오브젝트의 메소드를 호출하는데, 이렇게 메소드를 호출하는 전/후로 부가기능(공통 모듈)을 제공할 수 있다.
이런식으로 독립적으로 개발한 부가기능 모듈을 다양한 타깃 오브젝트의 메소드에 다이내믹하게 적용해주기 위해 가장 중요한 역할을 맡고 있는게 프록시고, 스프링 AOP는 프록시 방식의 AOP라 할 수 있다.

예시

AOP를 이용해 시간측정 Bean(ExampleService) 개선 - Execution expression

  1. 공통 모듈분석
    ⇒ 위 코드(ExampleServiceImpl)을 보면 StopWatch 를 이용해 성능측정을 하는부분이 start, process , end 메서드에 모두 포함된다.
    그렇기 때문에 해당 코드는 공통모듈로 묶어서 정의할 수 있다.

  2. 공통 모듈추출 및 구현

package io.security.corespringsecurity.aopsecurity;

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

@Component
@Aspect
public class PerfAspect {
		// io.security.corespringsecurity.aopsecurity.ExampleService 클래스내의 모든 메서드에 공통 모듈을 적용한다. 
    @Around(value = "execution(* io.security.corespringsecurity.aopsecurity.ExampleService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object retVal = pjp.proceed();
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        return retVal;
    }
}
  1. 구현체 공통 모듈 삭제
package io.security.corespringsecurity.aopsecurity;

import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Component
public class ExampleServiceImpl implements ExampleService {
    @Override
    public void start() {
        try {
            Thread.sleep(1000);
            System.out.println("start");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process() {
        try {
            Thread.sleep(1000);
            System.out.println("processing");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void end() {
        try {
            Thread.sleep(1000);
            System.out.println("ended");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  1. 테스트 코드 작성
package io.security.corespringsecurity.aopsecurity;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ExampleServiceImplTest {

    @Autowired
    ExampleService service;

    @Test
    public void exampleTest() throws Exception {
        service.start();
        service.process();
        service.end();
    }
}

기존과 차이점이 있다면, @Aspect 를 적용하기위해 @SpringBootTest 어노테이션을 추가해서 해당 @Aspect를 등록해주고 ExampleService도 DI해줬다.
참고: Advice 정의(@Aspect)시 Point cut시점을 정의할 수 있는데 위 예제는 @Around로 정의되었지만
@Before나 @After와같은 어노테이션도 존재한다.

출처:https://catsbi.oopy.io/fb62f86a-44d2-48e7-bb9d-8b937577c86c

0개의 댓글