실습 내용과 함께 읽어보는 간략한 사용자 정의 Annotation 작성을 정리해보고 싶었는데

김아무개·2023년 5월 17일
0

Spring Boot 🍃

목록 보기
13/95
post-custom-banner

하루 지났다고 기억이 전혀 나질 않는다

한번 실습한거 안까먹고 영원히 기억하는 사람이었으면 얼마나 좋을까? ㅋㅋ

우선 파일 이름부터 나열!

그 전에

이 어노테이션을 정의 하게 된 이유와 사용 목적에 대해 알아보는게 좋을 것 같다.

그리고 다음엔 실습 후 바로 정리하기로 다짐..😠


이 어노테이션의 명칭은 AccountLock 이고

기능은 Account 계좌에 계좌 잔액 사용 / 사용 취소 요청 시

2중 3중 다중 접근 시도를 사전에 차단하는 Lock을 관리하는 기능이다.


왜 굳이 어노테이션을 만들어서 사용했을까?


일단, 어노테이션을 사용하면 코드의 가독성이 좋아진다.

메서드에 기능을 나열하지 않고 메서드 이름/ 클래스이름 근처에
어노테이션 호출만 해두면 되기 때문이다.


그리고 선언적 프로그래밍이 가능해진다.

어노테이션을 통해 개발자는 '무엇'을 하고 싶은지만 선언하면,
'어떻게'하는지는 프레임워크가 알아서 처리한다.

이를 통해 개발자는 비즈니스 로직에 더 집중할 수 있다.

따라서 유지보수가 쉬워지고, 코드의 이해가 단순해지는 큰 이점이 있다.


이제 파일을 분석해보자면 !

으어 어디보자

테스트 제끼고..

1. aop

  • AccountLock
  • AccountLockIdInterface

2. controller

  • TransactionController

3. dto

  • UseBalance
  • CancelBalance

4. service

  • LockService
  • LockAopAspect

5. type

  • ErrorCode

1. 커밋 기록을 따라서 파일의 사용 순서로 나열

       AccountLock

어노테이션 정의 ( 인터페이스 파일처럼 기능 선언만 하는 용도라고 생각됨 )

       TransactionController

@AccountLock 사용 위치

       LockAopAspect

@AccountLock 기능 정의

       AccountLockIdInterface

dto에 상속해서 사용될 인터페이스로, @AccountLock 에서 필요로 하는 값을 명세.

       CancelBalance

@AccountLock 에서 필요로 하는 객체가 있는 dto 클래스.
AccountLockIdInterface 를 상속 받아 구현한다.

       UseBalance

@AccountLock 에서 필요로 하는 객체가 있는 dto 클래스
AccountLockIdInterface 를 상속 받아 구현한다.

       LockService

여기서 Redisson을 사용하게 되는데, 
Redisson이 뭐하는 건지 알아야 분석이 가능할 듯 싶다.

       ErrorCode

Lock 제한 걸린 클라이언트에게 보여줄 메세지 정의

       : 내 기준 핵심 파일 표시

오 예쁘다 ㅎㅎ
눈에 확 들어오니 좋다
확실히 마크다운 문법은 작성할 때 편하긴 정말 편한데
가독성이 초큼..
별루....🙈

조만간 마크다운 지원 에디터 라이브러리 같은 걸 발견한다면
내 블로그를 내 손으로 개발해보는 작업에 들어갈지도 모르겠다.ㅋㅋ +_+
꿈은 클수록 좋다지
엣헴


2. 파일 흐름 따라가보기

  1. 사용자 정의 Annotation 명세
    AccountLock 파일 작성
@Target(ElementType.METHOD) // 메서드에서 사용됨
@Retention(RetentionPolicy.RUNTIME) // 런타임 시 붙음
@Documented // 문서화시 문서에 포함 됨
@Inherited  // 상속 됨
public @interface AccountLock {
    long tryLockTime() default 5000L; // 이 속성(tryLockTime())의 기본값은 5000L임
}
  1. TransactionController에서 어디에 사용 될 지 미리 앉혀놓기 이런식으로 사용!

  2. AccountLock 어노테이션 기능 구현
    LockAopAspect라는 파일을 생성해서 이곳에 AccountLock 어노테이션의 기능을 정의 했다.


import com.zhyun.account.aop.AccountLockIdInterface;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LockAopAspect {
    private final LockService lockService;

    @Around("@annotation(com.zhyun.account.aop.AccountLock) && args(request)") 
    public Object aroundMethod(		ProceedingJoinPoint pjp,
						            AccountLockIdInterface request		) throws Throwable {    
                                    
        lockService.lock(request.getAccountNumber());
        try {
        
            return pjp.proceed(); 
            
        } finally {
            lockService.unlock(request.getAccountNumber());
        }
    }

}

이렇게 까지 분석해봐야 하나 정말 깊은 생각을 잠시 했지만,
이왕 손댄김에 계속 해보기르 ..🙈
사서 고생하는걸 좋아하는 편이었던 것일까? 🥲
정신이 몽롱해져서 판단이 잘 안선다.
언젠가 필요로 하겠지 !

🥲

근데 낮과 오후엔 잘만 나던 벨로그 오류가 왜 새벽엔 안날까?
차라리 오류라도 나면..🥲ㅋㅋ
못된 생각을 잠시 해본다 🙈
정신 차리고 다시 해봐야지


1. 클래스 생성 및 클래스 단위 어노테이션 부착

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LockAopAspect {

}

@Aspect

현재 클래스가 Aspect 클래스임을 나타낸다.
Aspect 클래스는 여러 객체에 걸쳐 사용되는 기능(예: 로깅, 보안 등)을 모듈화하는데 사용된다.

@Component

클래스가 Spring의 Bean으로 관리되어야 함을 나타냄.

@Slf4j

간편한 로그 사용 환경제공하는 라이브러리!

@RequiredArgsConstructor

final 또는 @NonNull 필드만을 인자로 하는 생성자를 생성


2. 클래스 생성 및 클래스 단위 어노테이션 부착

   @Aspect
   @Component
   @Slf4j
   @RequiredArgsConstructor
   public class LockAopAspect {
01     private final LockService lockService;

02     @Around("@annotation(com.zhyun.account.aop.AccountLock) && args(request)")
03     public Object aroundMethod(		ProceedingJoinPoint pjp,
04  	                               	AccountLockIdInterface request  ) throws Throwable 
05 	{    
           // lock 취득 시도
06         lockService.lock(request.getAccountNumber());
07         try {
               // before
08             return pjp.proceed(); // aop를 걸어준 부분을 동작 시킴
               // after
   
09         } finally {
               // aop걸어준 부분이 정상/실패 구분없이 동작한 후 lock 해제
10             lockService.unlock(request.getAccountNumber());
11         }
12     }
   }

01 : private final LockService lockService;

LockService 를 통해 Controller와 Lock을 제어하는 교류를 해야 하기 때문에 작성.


02 : @Around("@annotation(com.zhyun.account.aop.AccountLock) && args(request)")

aspectJ 문법이라고 한다.

Around 어노테이션에 매개변수로 어노테이션 파일 위치(패키지경로)를 포함한
이 파일의 내용이 적용 될 어노테이션을 명시 해주어야 한다.

그리고 뒤에 붙은 args(request)는
이 어노테이션이 사용된 메서드의 매개변수에서
args()에 명시한 자료형을 가져와 사용함을 의미한다.

그렇기 때문에,
이 어노테이션을 사용하는 메서드에서는
AccountLockIdInterface 를 구현한 객체가 명시 되어 있어야 한다.


03 ~ 12 : public Object aroundMethod(){ .. }

실질적인 어노테이션 기능 구현 메서드.

lockService를 통해 lock을 실행 한 후

매개변수로 받은 ProceedingJoinPoint 객체(= 메서드를 실행/제어하는 객체)를 통해
실제 메서드를 동작 시키고 (= pjp.proceed(); )

pjp.proceed(); 동작이 끝나면
lockService를 통해 lock을 해제한다.


이게 전부인것 같은데

나중에 개발력이 좀 더 업그레이드 되면 다시 살펴봐야겠다.

글 쓰고 나서 보니 어노테이션을 작성해서 사용하는 부분은 크게 어렵거나 복잡하지 않았다.

단지, 사용한 실습 파일이 처음 접하기에는 난이도가 높았던것 같다는 생각이 들었다.

오늘은 벌써 새벽4시를 바라보는 시점이라

더 이상 정리하는것은 무리이고

다음에 또 사용해 볼 기회가 오면

간단한 어노테이션 생성 및 사용 예제를

새로 작성해보는 것도 정말 좋을 것 같다는 생각을 해보고

오늘은 20000 😶‍🌫️


ㅋㅋ 과제 1 제출하고 봤더니 씻고 출근하게생김
오랜만에 샘김노래나 한곡 들어봐야지

profile
Hello velog! 
post-custom-banner

0개의 댓글