22.06.29 AOP

AOP란 (Aspect-Oriented-Programming)




mvnrepository - AspectJ Weaver » 1.9.6
pom.xml에 설정 추가
<!-- aspectjweaver: AOP를 자바 클래스에 적용해주는 라이브러리 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
<scope>runtime</scope>
</dependency>
srvlet-config 네임스페이스에 aop 추가
공통 로그들, 예외 처리 내용들을 기존 클래스와 분리해서
객체 지향적으로 사용하기 위해
Aspect(공통 로직들)와 Target(Service 클래스들,메서드들)을 연결할 수 있도록
가상 환경을 구축해 주는 빈.
<aop:aspectj-autoproxy />
log4j.xml생성
자바를 이용한 백엔드 로직을 작성하다 보면,
결과를 확인하기 위해 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:/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, errorm warn...)
%m -> 메세지
%c -> 전체 패키지명 또는 파일 이름(%C -> 클래스이름)
%d -> 이벤트 발생 시각(yyyy-MM-dd HH:mm:ss)
숫자: 공백, 글자가 차지할 공간. 음수로 주면 좌측정렬, 양수 주면 우측 정렬
-->
<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:/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>
<!-- log4j의 여러가지 로그 레벨
FATAL (가장 높음) - 가장 심각한 문제가 발생할 때 사용
ERROR - 문제가 발생한 상태
WARN - 오류의 원인이 될 수 있는 메세지
INFO - 상태 변경 같은 실제 어플리케이션의 운영과 관련되 로직
DEBUG - 디버깅 용도
TRACE (가장 낮음) - 가장 상세한 로깅 정보를 출력
-->
<!-- aop 패키지를 로그 레벨로 추가 -->
<logger name="com.spring.myweb.util.aop">
<level value="info" />
</logger>
<script>
package com.spring.myweb.util.aop;
@Aspect //AOP를 적용시킬 클래스
@Component //빈 등록
public class LogAdvice {
private static final Logger logger = LoggerFactory.getLogger(LogAdvice.class);
/* 준비하신 로직(advice)을 어떤 시점(joint point)에서 사용하게 할 지를 정해주실 수가 있습니다. (point Cut)
@before,@after,@afterThrowing
@around는 위에 있는 세가지 pointCut을 한번에 처리할 수 있도록 해 줍니다.
메서드 실행 권한을 가지고, 타겟 메서드랑 접목시켜서 사용.
규칙 - 반환타입은 Object, 매개변수로 메서드의 실행 시점을 결정짓는 ProceedingJoinPoint를 선업합니다.
ProceedingJoinPoint는 AOP의 대상이 되는 Target이나 파라미터 등을 파악할 뿐만 아니라
직접 실행을 결정할 수도 있습니다.
execution(accessModi package class method arguments)
*/
//접근제한자 상관없음, com.spring.myweb으로 시작하는 패키지, 중간에 뭐 들어가는 지 상관없고
//서비스패키지 안에 있는 ~~Service로 끝나는 클래스의 모든 메서드(매개변수 관계없음)
@Around("execution(* com.spring.myweb.*.service.*Service.*(..))")
public Object aroundLog(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환경에서 돌아가는 중이기 때문에
//proceed()의 결과를 반환해야 메서드의 정상 흐름으로 돌아갑니다.
return result;
}
}
</script>
mvnrepository -Log4Jdbc Log4j2 JDBC 4 1
SQL Logger 출력할 수 있게 도와주는 라이브러리
pom.xml에 설정 추가
<!-- log4jdbc-log4j2-jdbc4.1 (DB log 출력) -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
<!-- SQL Logger -->
<!-- DB 연결에 관련된 이벤트를 기록(Connection pool 등) -->
<logger name="jdbc.connection" additivity="false">
<level value="warn" /> <!-- warn이상만 출력 -->
<appender-ref ref="console" />
</logger>
<!-- ResultSet를 제외한 모든 JDBC 호출 내역을 기록. -->
<logger name="jdbc.audit" additivity="false">
<level value="warn" />
<appender-ref ref="console" />
</logger>
<!-- ResultSet를 포함한 모든 JDBC 호출 내역을 기록. -->
<logger name="jdbc.resultset" additivity="false">
<level value="warn" />
<appender-ref ref="console" />
</logger>
<!-- SQL문만 기록.(?값이 드러납니다.) -->
<logger name="jdbc.sqlonly" additivity="false">
<level value="info" />
<appender-ref ref="console" />
</logger>
<!-- teble 모양으로 조회된 내용을 기록합니다. -->
<logger name="jdbc.resultsettable" additivity="false">
<level value="info" />
<appender-ref ref="console" />
</logger>
<!-- 해당 SQL을 실행시키는 데 소요된 시간 정보(밀리초) -->
<logger name="jdbc.sqltiming" additivity="false">
<level value="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>
클래스에서 사용할때는 변수 선언 후 사용
private static final Logger logger = LoggerFactory.getLogger(UserController.class);