Today
-
Yesterday
-
Total
-
  • 실습 내용과 함께 읽어보는 간략한 사용자 정의 Annotation 작성을 정리해보고 싶었는데
    Spring Boot 🍃 2023. 12. 2. 00:01

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

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

    우선 파일 이름부터 나열!

    그 전에

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

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


    이 어노테이션의 명칭은 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 제출하고 봤더니 씻고 출근하게생김 오랜만에 샘김노래나 한곡 들어봐야지

    'Spring Boot 🍃' 카테고리의 다른 글

    spring boot 프로젝트 git 업로드 시, API key 및 DB 접속정보 숨기기  (0) 2023.12.02
    Persistence  (0) 2023.12.02
    lombok : @Builder , @SuperBuilder  (0) 2023.12.01
    Mockito : ArgumentCaptor  (0) 2023.12.01
    Mockito  (0) 2023.12.01

Designed by Tistory / Custom by 얼거스