용어
Target
Joint Point
Advice
PointCut
메서드마다 공통으로 작성해야 하는 로직이 존재한다면 해당 로직을 작성
Advice 동작 위치
PointCut
@Around annotation
Log를 출력해서 적용하는게 AOP의 가장 유사한 예시
Logger객체
Code
package com.spring.myweb.util.aop;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
// AOP를 적용시킬 클래스
@Component
// Bean등록
public class LogAdvice {
private static final Logger logger = LoggerFactory.getLogger(LogAdvice.class);
// 로그를 찍기 위해 변수 선언
// LogAdvice 클래스의 로그를 찍기 위해 작성
// 공통 코드(로깅, 에러처리)를 수행하는 객체
// execution(accessModi package class method arguments)
@Around("execution(* com.spring.myweb.*.service.*Service.*(..))")
// 모든 접근제한자, myweb의 모든 곳의 service패키지의 Service로 끝나는 클래스의 모든 메서드에 매개변수도 상관없다
//
// 준비한 로직(advice)을 어떤 시점(joint point)에서 사용하게 할 지를 정할 수 있음 (pointCut)
// @before, @after, @afterThrowing
// @around는 위에 있는 세가지 pointcut을 한번에 처리할 수 있음
// 메서드 실행 권한을 가지고 타겟 메서드랑 접목시켜서 사용
// 규칙 : 반환 타입은 Object, 매개변수로 메서드의 실행 시점을 결정 짓는 ProceedingJoinPoint를 선언
// ProceedingJoinPoint는 AOP의 대상이 되는 Target이나 파라미터 등을 파악할 뿐만 아니라 직접 실행을 결정할 수 있음
public Object arroundLog(ProceedingJoinPoint jp) {
long start = System.currentTimeMillis();
logger.info("실행 중인 클래스 : " + jp.getTarget());
logger.info("실행 메서드 : " + jp.getSignature().toString());
logger.info("매개 값 : " + Arrays.toString(jp.getArgs()));
Object result = null;
try {
result = jp.proceed();
// 타겟 메서드의 실행
} catch (Throwable e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
logger.info("메서드 소요 시간 : " + (end - start) * 0.001 + "초");
// 위에 작성한 이 메서드의 실행 내용은 proxy 환경에서 돌아가는 중이기 떄문에
return result;
// proceed() 메서드의 결과를 반환해야 메서드의 정상 흐름으로 돌아감
}
}
로그 레벨 (높은 순으로 배치)
로그 파일 생성
<!-- 날짜별 로그 파일 생성 -->
<appender name="rollingFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="C:/LOG/all.log"/>
<!-- 로그의 내용을 특정 디렉토리에 저장할 수 있음 -->
<param name="Append" value="true"/>
<!-- param name="MaxFileSize" value="100MB"/ -->
<!-- param name="MaxBackupIndex" value="2"></param -->
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<!--
%p : 로그 레벨 출력 첨부(info, error, warn)
%m : 로그 메세지 첨부
%c : 전체 패키지 명 또는 파일 이름 첨부
%d : 이벤트 발생 시각 (yyyy-mm-dd ...) 첨부
-->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%C{10}] %m [%X{userId}]%n" />
</layout>
</appender>
DB log출력
SQL Logger
logger와 level 태그를 활용해서 패키지마다 로그의 레벨을 조절할 수 있음
Code
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!--
자바를 이용한 백엔드 로직을 작성하다 보면, 결과를 확인하기 위해
System.out.println()를 사용해왔음
System.out.println()은 단순 출력 이상의 기능을 수행할 수 없기 때문에
로그에 대한 다양한 기능을 제공하는 log4j 라이브러리를 사용
-->
<!-- Appenders -->
<!-- appenders : 로그의 출력 위치(파일 ,콘솔, DB등)를 결정 -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
<!-- 출력 형식 지정 가능 -->
</layout>
</appender>
<!-- 날짜별 로그 파일 생성 -->
<appender name="rollingFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="C:/Spring/LOG/all.log"/>
<param name="Append" value="true"/>
<!-- param name="MaxFileSize" value="100MB"/ -->
<!-- param name="MaxBackupIndex" value="2"></param -->
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<!--
%p : 로그 레벨 출력 첨부(info, error, warn)
%m : 로그 메세지 첨부
%c : 전체 패키지 명 또는 파일 이름 첨부 (%C : 클래스 이름 )
%d : 이벤트 발생 시각 (yyyy-mm-dd ...) 첨부
숫자 : 공백, 글자가 차지할 공간, 음수로 주면 좌측정렬, 양수 주면 우측정렬
-->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%C{10}] %m [%X{userId}]%n" />
</layout>
</appender>
<!-- 날짜별 로그 파일 생성(에러만) -->
<appender name="errFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="Threshold" value="ERROR"/>
<param name="File" value="C:/Spring/LOG/error.log"/>
<param name="Append" value="true"/>
<!-- param name="MaxFileSize" value="100MB"/ -->
<!-- param name="MaxBackupIndex" value="2"></param -->
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %5p [%C{1}] %m [%X{userId}]%n" />
</layout>
</appender>
<!-- aop 패키지를 로그 레벨로 추가 -->
<logger name="com.spring.myweb.util.aop">
<!-- aop패키지 경로를 name에 지정 -->
<level value="info" />
<!-- <level value="error" /> -->
<!-- value에 여러가지 로그 레벨을 지정할 수 있음
FATAL, ERROR, WARN, INFO, DEBUG, TRACE
-->
</logger>
<!-- Application Loggers -->
<logger name="com.spring.myweb">
<level value="info" />
</logger>
<!-- 3rdparty Loggers -->
<logger name="org.springframework.core">
<level value="info" />
</logger>
<logger name="org.springframework.beans">
<level value="info" />
</logger>
<logger name="org.springframework.context">
<level value="info" />
</logger>
<logger name="org.springframework.web">
<level value="info" />
</logger>
<!-- SQL LOGGER -->
<!-- DB연결에 관련된 이벤트를 기록(Connection pool 등)
문제가 발생한다면 해당 내용만 출력 -->
<logger name = "jdbc.connection" additivity="false">
<level valuie="warn"/>
<appender-ref ref="console" />
</logger>
<!-- Resultset을 제외한 모든 JDBC 호출 내역을 기록 -->
<logger name = "jdbc.audit" additivity="false">
<level valuie="warn"/>
<appender-ref ref="console" />
</logger>
<!-- Resultset을 포함한 모든 JDBC 호출 내역을 기록 -->
<logger name = "jdbc.resultset" additivity="false">
<level valuie="warn"/>
<appender-ref ref="console" />
</logger>
<!-- sql문만 기록하는 로그(?값이 드러남) -->
<logger name = "jdbc.sqlonly" additivity="false">
<level valuie="info"/>
<appender-ref ref="console" />
</logger>
<!-- table 모양으로 조회된 내용을 기록 -->
<logger name = "jdbc.resultsettable" additivity="false">
<level valuie="info"/>
<appender-ref ref="console" />
</logger>
<!-- 해당 sql을 실행시키는데 소요된 시간 정보 기록(밀릴초) -->
<logger name = "jdbc.sqltiming" additivity="false">
<level valuie="info"/>
<appender-ref ref="console" />
</logger>
<!-- Root Logger -->
<root>
<priority value="info" />
<appender-ref ref="console" />
<!-- 위에서 작성한 내용을 참고할 수 있음 -->
<appender-ref ref="errFile" />
<appender-ref ref="rollingFile" />
</root>
</log4j:configuration>
절차