Spring-MyWeb AOP

정원·2022년 6월 29일

Spring-MyWeb

목록 보기
16/16

22.06.29 AOP

AOP

AOP란 (Aspect-Oriented-Programming)

  • (관점지향프로그래밍)더욱 객체지향답게 의미를 갖는다
  • 공통 코드, 개별코드(비즈니스 로직) 를 분리해서 작성한다.
  • ex) java의 공통 기능을 부모클래스로 정의하고 상속 관계로 사용
  • 기존 코드를 수정하지 않고, 외부에서 원하는 기능에 접근하여 결합

AOP용어

라이브러리 추가

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 />

log4 사용

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>

LogAdvice

<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>

SQL Logger

라이브러리 추가

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.log4j2.properties 생성

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

log4j.xml 추가 설정

	<!-- 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);

0개의 댓글