spring boot #17

·2022년 5월 16일
0

spring

목록 보기
18/22

💬 AOP

Aspect-Oriented Programming

주요기능 외 부가기능들을 특정 지점에 삽입하는 프로그래밍 방법.
더욱 간결하고 효율적인 프로그래밍이 가능하게 해준다.

@Aspect //부가기능 주입을 위한 AOP클래스 선언
@Pointcut //주입 대상 지정
@Before // 대상 실행 이전에 수행
@After //대상 실행 후 수행
@AfterReturning // 대상 실행 - 정상 시 수행
@AfterThrowing // 대상 실행 - 예외 발생 실행 시 수행
@Around // 대상 실행 전후로 수행

댓글 서비스 입출력 값 확인을 위한 로깅과
특정 메소드의 수행 시간을 측정하는 AOP를 실습해보겠다.

댓글 서비스 입출력 값 로깅

public CommentDto create(Long articleId, CommentDto dto) {
        log.info("입력값 =>{}",articleId);
        log.info("입력값 =>{}",dto);

        //게시글 조회 및 예외 처리
        Article article = articleRepository.findById(articleId)
                .orElseThrow(()-> new IllegalArgumentException("댓글 생성 실패 ! 대상 게시글이 없다."));

        //댓글 엔티티 생성
        Comment comment = Comment.createComment(dto,article);

        //엔티티를 db에 저장
        Comment created = commentRepository.save(comment);

        //dto로 변경하여 반환

        CommentDto createdDto = CommentDto.createCommentDto(created);
        log.info("반환값 => {}",createdDto);
        return createdDto;
    }

이런식으로 코드에 직접 추가할 수 있다.
하지만 logging 과 같은 부가적인 코드가 많아지면 코드가 번거럽고 더러워진다.

이러한 문제점을 AOP로 해결할 수 있다!!

◾ log AOP

@Aspect //AOP 클래스 선언 : 부가 기능을 주입하는 클래스
@Component //IoC 컨테이너가 해당 객체를 생성 및 관리
@Slf4j //로깅 기능
public class DebuggingAspect {


	//입력값 로깅 메소드
    //어떤 메소드를 대상 메소드로 선택할지!
    @Pointcut("execution(* com.example.firstproject.service.CommentService.*(..))")
    private void cut() {}


    //cut() 실행 이전에 수행 (실행 시점 설정)
    @Before("cut()")
    public void loggingArgs(JoinPoint joinPoint){
        //joinPoint는 cut()의 대상 메소드를 둘러싼 결합 지점

        //입력값 가져오기
        Object[] args = joinPoint.getArgs();

        //클래스명
        String className = joinPoint.getTarget()
                .getClass()
                .getSimpleName();

        //메소드명
        String methodName = joinPoint.getSignature()
                .getName();

        //입력값 로깅하기
        for(Object obj : args){
            log.info("{}#{}의 입력값 => {}",className ,methodName, obj);
        }
    }


	//반환값 로깅 메소드
    @AfterReturning(value = "cut()", returning = "returnObj")
    public void loggingReturnValue(JoinPoint joinPoint, 
                                   Object returnObj) { 
                                   
    	//joinPoint는 cut()의 대상 메소드
		//returnObj는 cut()의 리턴값
    
        //클래스명
        String className = joinPoint.getTarget()
                .getClass()
                .getSimpleName();

        //메소드명
        String methodName = joinPoint.getSignature()
                .getName();

        //반환값 로깅
        log.info("{}#{}의 반환값 => {}",className ,methodName, returnObj);
    }
}

AOP 대상 범위 변경

예를 들어 create() 메소드 하나를 대상으로 할 수도 있고,
CommentService.java에 있는 모든 메소드를 대상으로 설정할 수도 있다.

"execution(* com.example.firstproject.service.CommentService.create(..))"

"execution(* com.example.firstproject.service.CommentService.*(..))"

◾ 수행 시간 측정 AOP

댓글 서비스 삭제 기능의 수행 시간을 측정해보겠다.

어노테이션 자바 클래스인 RunningTime.java

@Target({ElementType.TYPE, ElementType.METHOD}) //어노테이션 적용 대상
@Retention(RetentionPolicy.RUNTIME) //어노테이션 유지 기간을 런타인까지 유지하겠다.
public @interface RunningTime {
}

PerformanceAspect.java

@Aspect
@Slf4j
@Component
public class PerformanceAspect {


    //특정 어노테이션을 대상 지정
    @Pointcut("@annotation(com.example.firstproject.annotation.RunningTime)")
    private void enableRunningTime(){}


    //기본 패키지의 모든 메소드를 대상 지정
    @Pointcut("execution(* com.example.firstproject..*.*(..))")
    private void cut(){}


    //실행 시점 설정 : 두 조건을 만족하는 대상을 전후로 기능을 삽입
    @Around("cut() && enableRunningTime()")
    public void loggingRunningTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //그 대상을 실행까지 할 수 있는 joinPoint

        //메소드 수행 전에 시간 측정 시작
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        //메소드를 수행
        Object returningObj = joinPoint.proceed();

        //메소드명
        String methodName = joinPoint.getSignature()
                .getName();

        //메소드 수행 완료 후 측정 종료 및 로깅
        stopWatch.stop();
        log.info("{}의 총 수행 시간 => {} sec",methodName,stopWatch.getTotalTimeSeconds());
    }
}

측정할 메소드에 @RunningTime 어노테이션 추가

CommentApiController.java

  //댓글 삭제 메소드
    @RunningTime
    @DeleteMapping("/api/comments/{id}")
    public ResponseEntity<CommentDto> delete(@PathVariable Long id){
        CommentDto deletedDto= commentService.delete(id);
        return ResponseEntity.status(HttpStatus.OK).body(deletedDto);
    }

아니 근데 나는 왜 한글 출력이...아웅 귀차나

.
.
.
.
.
.
.

IntelliJ 한글 깨짐 수리
IntelliJ vmoptions 설정

/bin/idea64.exe.vmoptions
-Dfile.encoding=UTF-8 추가

0개의 댓글

관련 채용 정보