Spirng AOP를 이용하여 Service클래스에 로그 찍기

들어가기

Spring MVC 프로젝트에서 Service에 Aop Advice를 걸어서 log4j로그를 찍는 예제이다. xml설정이 아닌 어노테이션을 이용할 것이다.


특정 패키지의 모든 service 클래스가 동작할때 파라미터등 기타 정보를 출력하는 로그와 메소드가 동작하면서 걸린 시간을 로그하는 예제이다.

AOP 기초 설정하기

1.pom.xml에 라이브러리 추가.

일단 properties에 aspect 공통 버전을 설정한다.

1
2
3
4
5
6
<properties>
<java-version>1.8</java-version>
<org.springframework-version>4.3.8.RELEASE</org.springframework-version>
<org.aspectj-version>1.8.9</org.aspectj-version> <!-- aspoect 버전 설정 -->
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

그리고 spring aop, aspectj 라이브러리를 추가한다. AspectJ는 자바용 AOP 지원을 제공할 목적으로 시작된 라이브러리다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework-version}</version>
</dependency>

<!-- 트랜잭션 처리용 라이브러리 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>

<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${org.aspectj-version}</version>
</dependency>

2.root-context.xml 설정하기.

root-context.xml의 namesspaces탭에서 aop, tx 네임스페이스를 추가하자.

그리고 root-context.xml파일에 아래 내용을 추가하자.

1
2
3
4
5
<!-- AspectJ라이브러리를 이용한 Proxy 객체를 생성 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!-- XML 방식으로 AOP 기능을 설정할 때 사용 : 이 예제에는 어노테이션을 사용하므로 필요없긴 하다.-->
<aop:config></aop:config>

3.Advice 클래스 생성하기.

특정 패키지에 SampleAdvice 클래스를 생성하자. 내용은 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.hanumoka.sample.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
@Aspect
public class SampleAdvice {

private static final Logger logger = LoggerFactory.getLogger(SampleAdvice.class);

//@Before("execution(* com.hanumoka.sample.service.BoardService*.*(..))")
//target 메소도의 파라미터등 정볼르 출력한다.
@Before("execution(* com.hanumoka.sample.service.*.*(..))")
public void startLog(JoinPoint jp) {

logger.info("-------------------------------------");
logger.info("-------------------------------------");

/* 전달되는 모든 파라미터들을 Object의 배열로 가져온다. */
logger.info("1:" + Arrays.toString(jp.getArgs()));

/* 해당 Advice의 타입을 알아낸다. */
logger.info("2:" + jp.getKind());

/* 실행하는 대상 객체의 메소드에 대한 정보를 알아낼 때 사용 */
logger.info("3:" + jp.getSignature().getName());

/* target 객체를 알아낼 때 사용 */
logger.info("4:" + jp.getTarget().toString());

/* Advice를 행하는 객체를 알아낼 때 사용 */
logger.info("5:" + jp.getThis().toString());

}

//target 메소드의 동작 시간을 로그한다.
@Around("execution(* com.hanumoka.sample.service.*.*(..))")
public Object timeLog(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
logger.info(Arrays.toString(pjp.getArgs()));

//실제 타겟을 실행하는 부분이다. 이 부분이 없으면 advice가 적용된 메소드가 동작을 안할것 같다.
Object result = pjp.proceed(); //proceed는 Exception 보다 상위 Throwable을 처리해야 한다.

long endTime = System.currentTimeMillis();
logger.info(pjp.getSignature().getName() + " : " + ( endTime - startTime)); //target 메소드의 동작 시간을 출력한다.
logger.info("==============================");

//Around를 사용할 경우 반드시 Object를 리턴해야 한다.
return result;
}
}

스프링 컨테이너가 위 클래스를 인식할수 있도록, @Component 어노테이션이 적용되어 있다. 물론 root-context.xml에서 해당 패키지를 반드시 스캔 해야 한다.

어노테이션은 @Before, @Around 두개만 사용하였다. com.hanumoka.sample.service 패키지의 모든 클래스의 모든 메소드를 대상으로 한다. 코드의 주석을 보면 대충 내용을 알수 있을 것이다.

위 소스가 적용되면 STS에서 Aop를 소스상 표시해준다. (난 여태 이 의미를 모르고 있었다.)

이미지를 클릭하여, 노란색 마킹을 보라.

Advice 클래스의 메소드에는 빨간 화살표가 바깥을 향하고, 이 Advice가 적용되는 Target클래스의 메소드는 빨간 화살표가 바깥에서 안쪽을 향하고 있다. 이것은 AOP관련 표시를 STS에서 자동으로 해주는 것이다.

com.hanumoka.sample.service 를 사용하는 컨트롤러를 동작 시켜보자.

아래처럼 로그가 찍힌다.

끝!!!