Aspect-Oriented-Programming

Let's Just Go·2022년 8월 22일
0

Spring

목록 보기
26/26

Spring

AOP

정의

  • 정의
    • AOP는 비즈니스 로직을 처리하는 곳 어디든 위치할 수 있음
    • 기존 코드를 수정하지 않고 외부에서 원하는 기능에 접근하여 결합
    • 공통 코드, 개별 코드(비즈니스 로직)를 분리해서 작성


용어

  • 용어

    • Target

      • 개발자가 작성한 클래스 (Service, Controller 등)라고 보면 됨
    • Joint Point

      • Target의 메서드(Service클래스 안의 메서드)
    • Advice

      • 공통 코드(로깅, 에러처리)
    • PointCut

      • Advice를 어떤 Joint Point에 결합할 것인지 설정 (공통 코드를 어떤 메서드에 적용할 것인지 )


설정

  • AOP 설정
    • pom.xml에 라이브러리 다운
      • aspectj weaver 설치
      • AOP를 자바 클래스에 적용해주는 라이브러리
    • servlet-context
      • namespace에 aop체크
      • aop로 시작하는 태그 추가
      • <aop:aspectj-autoproxy />
        • 공통 로그들, 예외처리 내용들을 기존 클래스와 불리해서 객체 지향적으로 사용하기 위해 Aspect(공통 로직들)와 Target(Service클래스들, 메서드들)을 연결할 수 있도록 가상 환경을 구축해주는 Bean

AOP 객체 생성

  • AOP 객체 생성
    • 메서드마다 공통으로 작성해야 하는 로직이 존재한다면 해당 로직을 작성

    • Advice 동작 위치

      • @Before : 메서드를 호출 전 실행
      • @After : 메서드를 호출 후 실행
      • @AfterThrowing : 메서드 예외 발생 시 동작
      • @Around : 메서드에 결합해서 처리, 반환 유형이 존재
    • PointCut

      • Advice를 어떤 JointPoint에 결합한 것인지 설정 (공통 코드를 어떤 메서드에 적용시킬 것인지)
    • @Around annotation

      • execution(accessModi package class method arguments)
      • @Around("execution( com.spring.myweb..service.Service.(..))")
      • 모든 접근제한자, myweb의 모든 곳에 service패키지의 Service로 끝나는 클래스의 모든 메서드에 어떤 매개변수도 상관없다 라는 뜻
    • Log를 출력해서 적용하는게 AOP의 가장 유사한 예시

      • target에 공통 코드인 로그를 출력하게 할 수 있으므로
    • Logger객체

      • 실행 과정을 Log로 확인하기 위해 사용
      • Logger객체.info()를 통해 execute에 지정한 메서드들의 과정을 log로 확인 가능
      • log4j.xml에 등록
    • 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() 메서드의 결과를 반환해야 메서드의 정상 흐름으로 돌아감
      	}
      
      }

Log4j

Log Level

  • 로그 레벨 (높은 순으로 배치)

    • FATAL : 가장 심각한 문제가 발생할 때 표시할 수 있음
    • ERROR : 문제가 발생한 상태를 표시할 수 있음
    • WARN : 오류의 원인이 될 수 있는 메세지를 표시할 수 있음
    • INFO : 상태변경 같은 실제 어플리케이션의 운영과 관련된 로직을 표시할 수 있음
    • DEBUG : 디버깅 용도로 표시할 수 있음
    • TRACE : 가상 상세한 로깅 정보 출력할 수 있음
  • 로그 파일 생성

    • 설정한 기간 단위로 새 파일을 만들어 로그 메세지 기록
      <!-- 날짜별 로그 파일 생성 -->
          <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출력

    • Mybatis의 sql log를 보기 위해 사용
    • Log4Jdbc Log4j2 JDBC 4 1 라이브러리 다운
    • .properties 파일 하나 생성해서 기타 설정 내용 입력
    • Hikari.properties 파일의 내용도 수정
  • SQL Logger

    • DB연결에 관련된 이벤트 기록
  • 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>
    • 절차

      • 로그를 보고 싶은 클래스에 Logger객체를 선언
      • Logger객체로 보고 싶은 로그 정보 레벨을 지정하게 되면 로직의 로그를 볼 수 있음
      • log4j에 원하는 로그 내용만 볼 수 있도록 Setting을 지정하게 되면 Custom 할 수 있음
profile
안녕하세요! 공부한 내용을 기록하는 공간입니다.

0개의 댓글