IT/Spring | Java

[Spring] AOP 구현 + AspectJ 활용

힞뚜루마뚜루 2023. 5. 30. 16:14
728x90

의존성 추가

Maven

스프링 AOP를 사용하기 위해서는 아래와 같이 의존성을 추가해야 한다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

하지만!!!!!!
나는 더 많은 조인포인트 사용을 위해 AspectJ를 활용할 것이다.   
(이에 대해 자세한 내용은 다음 포스팅에.. <-- 숙제)

때문에 아래와 같이 AspectJ 라이브러리를 추가해줘야 한다. 이 때 자신의 스프링버전에 맞게 버전 수정이 필요하다.

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.9.8</version>
</dependency>

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.9.8</version>
</dependency>
  • Aspect RT 
    : AspectJ 기능 사용을 위한 AspectJ 런타임 프로그램
  • Aspect Weaver
    : aspect 정보를 바탕으로 aspect를 구성한 코드를 생성하는데 필요한 유틸리티 프로그램

 

그리고 최상위 클래스에 @EnableAspectJAutoProxy 라는 어노테이션을 추가한다. 

@SpringBootApplication
@Configuration
@ComponentScan
@EnableAspectJAutoProxy   //<-- 추가??
@EnableAutoConfiguration
@EnableScheduling
...
public class Application extends SpringBootServletInitializer {
+++++++++++++++
AspectJ의 @Aspect 어노테이션을 사용 가능하게 해준다는데, 사실 나는 이거 모르고 그냥 사용하고 있었는데도 별 문제가 없었다.
@EnableAspectJAutoProxy  <---  요게 있고 없고 차이가 뭐지...???? 추가안했는데도 왜 오류가 안났을까요? 아시는 분....
+++++++++++++++

 

Aspect 클래스 생성

메서드의 실행 시간을 측정해주는 로직이다.

@Component
@Aspect
public class PerfAspect {

    @Around("execution(* com.example..*.EventService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object reVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return reVal;
    }
}

@Aspect

@Aspect를 사용해 모듈화할 Aspect 클래스를 정의한다.

@Aspect는 Advisor를 만들어주는 역할만 하므로 컴포넌트 스캔이 되지 않는다. 따라서 아래 방법 중 하나로 스프링 빈 등록을 반드시 해줘야 한다.

  • @Bean 으로 수동 등록
  • @Component로 컴포넌트 스캔해서 자동 등록
  • @Import 사용해서 파일 추가

 

Advice

실질적으로 수행하는 로직이다.

스프링은 Advice와 관련해 메서드에 붙일 수 있는 5가지 어노테이션을 제공하는데, 이 어노테이션을 통해 해당 메서드의 advice 로직을 정의한다.
어노테이션 종류에 따라서 포인트컷에 지정된 대상 메서드에서 advice가 실행되는 시점을 정할 수 있다. 또한 속성값으로 포인트컷을 지정할 수 있다. 

  • @Around
    • advice가 타겟 메서드를 감싸 타겟 메서드 호출 전/후 실행
    • 아래 4개의 어노테이션을 모두 포함한다. (try catch finally 와 동일)
  • @Before
    • 조인포인트 실행 이전에 실행
  • @After
    • 조인포인트에서 실행 결과와 (메서드가 정상적으로 수행하든 예외를 던지든) 무관하게 실행
  • @AfterReturning
    • 조인포인트 정상 실행 완료 후 실행
    • 반환값 조작 불가능
  • @AfterThrowing
    • 메서드가 예외를 던지는 경우 실행
    • 예외 조작 불가능

 

Pointcut 분리

위 예제에서는 advice 어노테이션 속성으로 포인트컷을 명시해서 사용했지만, 보통은 분리해서 사용한다.
분리해서 사용하는 습관을 들이자

@Component
@Aspect
public class PerfAspect {

	//pointcut분리
    @Pointcut("execution(* com.example..*.EventService.*(..))")
    private void logPointcut() {}
    
	//pointcut 적용
    @Around("logPointcut()")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
      ...
    }
}

 

 

마무리

라이브러리 추가 후 포인트컷 적용을 위해 포인트컷 정규표현식만 알면 Log 출력과 같은 간단한 AOP는 구현이 쉽다.

하지만 로그 출력하려고 aop 공부한 건 아니기 때문에 저거 활용해서 내가 쓸 건 따로 만들거임

 

728x90