본문 바로가기
Java Web Programming/6. Spring | MyBatis

[Spring] 스프링 AOP의 Around Advice를 통한 성능 확인 (+Log4j, StopWatch 라이브러리)

by 파프리카_ 2020. 10. 29.
728x90
반응형

[ 요구사항  시나리오]

기존 시스템의 성능을 체크한다.

서비스하는 각 메서드의 소요 시간을 레벨 별로 체크해서, 리포트를 제출해야 한다.

 

리포트는

0.5초 ~ 1초 소요 시에는 log.warn(target class명, 메서드 소요시간)

1초 초과 시에는 log.error(target class명, 메서드 소요시간)

 

* 유의사항 : Exception 발생 여부와 관계 없이, 모든 서비스 계열의 모든 메서드가 체크되어야 한다.

 

1. 로그 관련 라이브러리 (or 컴포넌트) 체크하기 → Log4j 라이브러리 사용

2. 소요 시간 체크 관련 라이브러리 체크하기 Spring StopWatch 사용

→ StopWatch 사용법 (Log4j로 일정 시간 이상 시, 에러로 체크)


/log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>        
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{10} (%F:%L) - %m%n" />
        </Console>
        <File name="file" fileName="report.log" append="true">
            <PatternLayout pattern="%d %-5p [%t] %C{10} (%F:%L) - %m%n" />
        </File>
    </Appenders>

    <Loggers>
        <Root level="warn">
            <AppenderRef ref="console" />
        </Root>	
        <!-- aop.common 하위의 패키지 이하 클래스들만 별도로 Logging 설정 
        	 - level은 info 이상 로깅되도록 하고,
        	 - root level의 로깅 정책을 이어받지 않는다는 설정을 한다.
        	   (additivity = "false")
        -->	
        <Logger name="kosta.aop" level="warn" additivity="false">
	        <AppenderRef ref="console" />
        	<AppenderRef ref="file"/>
        </Logger>
    </Loggers>
</Configuration>

Spring config (aop)

 

aop의 advice는 around로 적용

/spring-config.xml (aop 설정 체크!)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<bean id="boardService" class="kosta.board.BoardService"></bean>
	<bean id="memberService" class="kosta.member.MemberService"></bean>

	<bean id="reportAOP" class="kosta.aop.PerformanceReportService"></bean>
	
	<aop:config>
		<!-- 1. 횡단관심 대상 bean 선택 -->
		<aop:aspect ref = "reportAOP">
		
			<!-- 2. point-cut 지정 -->
			<!-- 패키지 : within / 상세하게 : execution / bean으로 : bean -->
			<!-- bean(*Service) : bean 중 Service로 끝나는 bean 선택 -->
			<aop:pointcut expression="bean(*Service)" id="pt"/>
			
			<!-- 3. adivce 방법 지정 -->
			<aop:around method="timeCheck" pointcut-ref="pt"/>
		</aop:aspect>
	</aop:config>
</beans>

/kosta.model

 

Exception 존재 이유 : 프로그램 수행 시, 예외가 발생했을 때 그에 맞는 적절한 대처를 하기 위함이다!

/MemberNotFoundException.java

package kosta.member;

public class MemberNotFoundException extends Exception {
	private static final long serialVersionUID = 1L;

		public MemberNotFoundException(String message){
			super(message);
		}
}

 

/MemberService.java

package kosta.member;

public class MemberService {
	
	public void findMember(){
		try {
			Thread.sleep(600);
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
		System.out.println("find member");
		
	}
	
	public void findAllMember(){
		try {
			Thread.sleep(1800);
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
		System.out.println("findAllMember");
	}
	
	public void deleteMember(String id) throws MemberNotFoundException{
		try {
			Thread.sleep(900);
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
		if(id==null)
			throw new MemberNotFoundException("member not found!!!");
		System.out.println("deleteMember");
	}
}

 

/BoardService.java

package kosta.board;

public class BoardService {	
	
	public String find(){		
		try {
			Thread.sleep(100); //0.1초
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
		System.out.println("find board");	
		return "게시물정보";
	}
	
	public String findAllList(){		
		try {
			Thread.sleep(700); //0.7초
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
		System.out.println("findAllList board");	
		return "게시물 리스트";
	}
}

/kosta.aop

 

횡단 관심사항 정의 클래스 (시간 체크) + Around Advice 하여 info & warn 발생 

/PerformanceReportService.java

package kosta.aop;

import org.apache.logging.log4j.LogManager;
//Around Advice를 이용
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

public class PerformanceReportService {

	Logger log = LogManager.getLogger(PerformanceReportService.class);
	
	public Object timeCheck(ProceedingJoinPoint point) throws Throwable {
		String className = point.getTarget().getClass().getName();
		String methodName = point.getSignature().getName();
		Object retValue= null;

		StopWatch watch = new StopWatch();
		try{
			watch.start();
			//실제 대상(core) 메서드 호출
			retValue = point.proceed();
		} finally { //예외 발생 여부와 관계없이 항상 시간 체크
			watch.stop();
			Long time = watch.getTotalTimeMillis();
			
			if (time >= 500 && time <= 1000) {
				log.warn(className+ "(" + methodName + ") : " + time);
			} else if (time > 1000) {
				log.error(className+ "(" + methodName + ") : " + time);
			}
		}
		return retValue;
	}
}

/test

 

/TestPerfomanceCheck.java

package test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import kosta.board.BoardService;
import kosta.member.MemberNotFoundException;
import kosta.member.MemberService;

/*
 * 기존 시스템의 성능을 체크한다.
   - 서비스하는 각 메서드의 소요 시간을 레벨 별로 체크해서, 리포트를 제출해야 한다.

	리포트는
	0.5초 ~ 1초 소요 시에는 log.warn(target class명, 메서드 소요시간)
	1초 초과 시에는 log.error(target class명, 메서드 소요시간)

 	* 유의사항 : Exception 발생 여부와 관계 없이, 모든 서비스 계열의 모든 메서드가 체크되어야 한다.
 */
public class TestPerfomanceCheck {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext factory
			= new ClassPathXmlApplicationContext("spring-config.xml");
		
		BoardService bs = (BoardService) factory.getBean("boardService");
		MemberService ms = (MemberService) factory.getBean("memberService");
		
		System.out.println("> main: " + bs.find());
		System.out.println("> main: " + bs.findAllList());
		
		ms.findMember();
		ms.findAllMember();
		
		try {
			ms.deleteMember(null); // 일부러 exception 내기
		} catch (MemberNotFoundException e) {
			System.out.println("> main: " + e.getMessage());
		} 
		
		factory.close();
	}
}

[ 결과 ]

 

728x90
반응형