[Web_3] STUSSY CLONE PROJECT 4 😢

08627Β·2022λ…„ 10μ›” 4일
2

Spring

λͺ©λ‘ 보기
12/13
post-thumbnail


πŸ“Œ AOP (관점 지ν–₯ ν”„λ‘œκ·Έλž˜λ°)
πŸ“Œ @μ–΄λ…Έν…Œμ΄μ…˜ 으둜 AOP κ΅¬ν˜„ν•˜κΈ°
🐊 @Aspect / @Pointcut / @Around / @Before
πŸ‘Ύ λ©”μ†Œλ“œ μ‹€ν–‰ μ‹œ 둜그 정보가 좜λ ₯λ˜λ„λ‘ ν•˜λŠ” @μ–΄λ…Έν…Œμ΄μ…˜
πŸ‘Ύ μœ νš¨μ„± 검사 @μ–΄λ…Έν…Œμ΄μ…˜

πŸ’‘ AOP (관점 지ν–₯ ν”„λ‘œκ·Έλž˜λ°)

'핡심' κΈ°λŠ₯κ³Ό 'λΆ€κ°€' κΈ°λŠ₯을 λ‚˜λˆ„μ–΄ κ°œλ°œν•˜λ„λ‘ ν•˜λŠ” 것.

μ£Ό λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 곡톡 κΈ°λŠ₯으둜 κ΅¬λΆ„ν•˜κ³ , 곡톡 κΈ°λŠ₯은 ν•„μš”ν•œ λ•Œ λΆˆλŸ¬μ™€ μ μš©ν•œλ‹€.

πŸ’‘ @μ–΄λ…Έν…Œμ΄μ…˜ 으둜 AOP κ΅¬ν˜„ν•˜κΈ°

μ–΄λ…Έν…Œμ΄μ…˜ λ§¨λ“€μ–΄μ„œ AOP κ΅¬ν˜„

🐊 @Aspect / @Pointcut / @Around

@Aspect ; AOP 곡톡 κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€μ— μ£ΌλŠ” μ–΄λ…Έν…Œμ΄μ…˜
@Pointcut ; μ£Ό λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ 따라가닀가 곡톡 κΈ°λŠ₯이 ν•„μš”ν•œ μ‹œμ (λ©”μ†Œλ“œ)에 포인트컷 μ–΄λ…Έν…Œμ΄μ…˜μ„ μ£Όμ–΄μ„œ κΈ°λŠ₯을 μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•œλ‹€.
@Around ; μ‹€ν–‰λ˜κΈ° μ „, 후에 λ™μž‘ν•œλ‹€. ( β€» 곡톡 κΈ°λŠ₯ μˆ˜ν–‰ 후에도 λ™μž‘ν•΄μ•Ό ν•˜λ―€λ‘œ proceed λ˜μ–΄μ§€λŠ” Objectλ₯Ό λ°˜ν™˜ν•΄μ£Όμ–΄μ•Ό 함 )

πŸ‘Ύ λ©”μ†Œλ“œ μ‹€ν–‰ μ‹œ 둜그 정보가 좜λ ₯λ˜λ„λ‘ ν•˜λŠ” @μ–΄λ…Έν…Œμ΄μ…˜

▫️ @LogAspect

@Retention(RetentionPolicy.RUNTIME) // μ–΄λ…Έν…Œμ΄μ…˜ λ©”λͺ¨λ¦¬λ₯Ό λ™μž‘ν•˜λŠ” λ™μ•ˆ 가지고 μžˆκ² λ‹€ .. (라이프사이클 μ„€μ •) 
@Target({ElementType.TYPE, ElementType.METHOD}) // μ–΄λ…Έν…Œμ΄μ…˜μ„ 달 수 μžˆλŠ” νƒ€μž…μ„ μ •ν•΄μ€€λ‹€
public πŸ“@interface LogAspect {
}

* ElementType.TYPE
β†’ 클래슀, μΈν„°νŽ˜μ΄μŠ€ (μ–΄λ…Έν…Œμ΄μ…˜ 포함), emum (μ—΄κ±°ν˜• ⁓ 집합 같은 ) νƒ€μž…

▫️ LogAop.java

@Slf4j
@Aspect // AOP κ΅¬ν˜„ ν΄λž˜μŠ€μ΄λ‹€
@Component // μŠ€ν”„λ§ IoC 빈 등둝
public class LogAop {

    @Pointcut("@annotation(com.stussy._.aop.annotation.LogAspect)")
    private void annotationLog() {} 
    // ➑️ @LogAspect μ–΄λ…Έν…Œμ΄μ…˜μ΄ 달린 지점


	// ➑️ annotationLog()이 μ‹€ν–‰λ˜λŠ” μ‹œμ μ˜ Before/After 에 μ•„λž˜μ˜ λ©”μ†Œλ“œλ₯Ό 싀행함   
    @Around("annotationLog()") 
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();

        CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
        String[] argNames = codeSignature.getParameterNames();

        StringBuilder argNameString = new StringBuilder();
        StringBuilder argDataString = new StringBuilder();

        for(int i = 0; i < args.length; i++) {
            argNameString.append(argNames[i]);
            argDataString.append(args[i].toString());
            if(i < args.length - 1) {
                argNameString.append(", ");
                argDataString.append(", ");
            }
        }
        log.info("Method Call -- {}.{}({}) >> {}",
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(),
                argNameString.toString(),
                argDataString.toString());

        Object result = joinPoint.proceed(); // ⭐ Target λ©”μ†Œλ“œ μ‹€ν–‰ μ œμ–΄

        log.info("Method Return -- {}.{}({}) >> {}",
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(),
                argNameString.toString(),
                result);

        return result;
    }
}

🦎 ( Proceeding ) JoinPoint

μ‘°μΈν¬μΈνŠΈλŠ” λŒ€μƒ 객체, λ©”μ„œλ“œ 및 μ „λ‹¬λ˜λŠ” νŒŒλΌλ―Έν„°μ— λŒ€ν•œ 정보듀( β†’ λ‘œμ§μ„ λΌμ›Œλ„£μ„ 수 μžˆλŠ” ν•©λ₯˜ 지점이 됨 )을 λͺ¨λ‘ λ°°μ—΄λ‘œ κ°€μ Έμ˜€λŠ” 객체이닀.

즉, JoinPoint둜 μ–΄λ…Έν…Œμ΄μ…˜μ„ λ‹€λŠ” 객체λ₯Ό μ‚¬μš©ν•  수 있음.

πŸ‘Ύ μœ νš¨μ„± 검사 @μ–΄λ…Έν…Œμ΄μ…˜

▫️ @ValidAspect

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ValidAspect {
}

▫️ ValidationAop.java

@Slf4j
@Aspect // AOP κ΅¬ν˜„ ν΄λž˜μŠ€μ΄λ‹€
@Component // μŠ€ν”„λ§ IoC 빈 등둝
public class ValidationAOP {

    @Pointcut("@annotation(com.stussy.stussy._.aop.annotation.ValidAspect)")
    private void annotationValid () {}
    // ➑️ @ValidAspect μ–΄λ…Έν…Œμ΄μ…˜μ΄ 달린 지점
	
    // ➑️ annotationValid()κ°€ μ‹€ν–‰λ˜λŠ” μ‹œμ μ˜ Before(μ „)에 μ•„λž˜μ˜ λ©”μ†Œλ“œλ₯Ό 싀행함
    @Before("annotationValid()")
    public void before(πŸ“JoinPoint joinPoint) throws Throwable { 
    	// 'μ „' μ—λ§Œ μ‹€ν–‰λ˜λ―€λ‘œ λ©”μ†Œλ“œμ—μ„œ Proceed ν•΄ 쀄 ν•„μš” μ—†μŒ.  

        Object[] args = joinPoint.getArgs();
        BeanPropertyBindingResult bindingResult = null; // 였λ₯˜ 정보 μ΄ˆκΈ°ν™”

        // log.info("args λ°°μ—΄ 0번째 >>> {}", args[0]);
        // log.info("args λ°°μ—΄ 1번째 >>>{}", args[1]);

        for (Object arg : args) {
            if (arg.getClass() == BeanPropertyBindingResult.class) {
                bindingResult = (BeanPropertyBindingResult) arg;
                break;
            }
        }

        if (bindingResult.hasErrors()) {
            log.info("ν™•μΈλ‘œκ·Έ : 잘 λ“€μ–΄κ°”λ‚˜μš”? > {}", bindingResult);

            Map<String, String> errorMap = new HashMap<String, String>();

            bindingResult.getFieldErrors().forEach(error -> {
            	log.error("μœ νš¨μ„± 검사 였λ₯˜ λ°œμƒ");
                log.info("Error: ν•„λ“œλͺ…({}), 메세지({})" + error.getField(), error.getDefaultMessage());
                errorMap.put(error.getField(), error.getDefaultMessage());
            });
            
            throw new CustomValidationException("Validation failed", errorMap); 
            // ➑️ μ—λŸ¬ μ •μ˜λœ Exception
        }
    }

    @AfterReturning(value = "annotationValid()", returning = "returnObj") 
    // returning ; 리턴 객체 κ°€μ Έμ™€μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ 함. 
    // ⭐ μ‹€ν–‰ 후에 AfterReturning 이 μžˆμ–΄μ•Όμ§€λ§Œ λ©”μ†Œλ“œλ‘œ λ‹€μ‹œ λŒμ•„κ°€κ²Œ 됨 ! 
    public void afterReturning(JoinPoint joinPoint, Object returnObj) {
        log.info("Validation success: {}", returnObj);
    }

}

🦎 @Around / @Before c.f

@Around : ProceedingJoinPoint λ₯Ό 가져와 λ©”μ†Œλ“œ 싀행을 μ œμ–΄ν•  수 μžˆλ‹€. 일반 JoinPoint도 μ‚¬μš© κ°€λŠ₯함.

@Before : μ „ν›„μ²˜λ¦¬κ°€ μ—†κ³ , μ–΄λ…Έν…Œμ΄μ…˜μ΄ 달린 λ©”μ†Œλ“œ μ‹€ν–‰ 전에 AOP λ‘œμ§μ„ μ‹€ν–‰ν•œλ‹€. proceed() μ—†μŒ.

🦎 BindingResult / BeanPropertyBindingResult

BindingResult λŠ” μΈν„°νŽ˜μ΄μŠ€λ‘œ, error 정보λ₯Ό 가지고 μžˆλŠ” 객체이닀.
μΈν„°νŽ˜μ΄μŠ€μ΄κΈ° λ•Œλ¬Έμ—, μ‹€μ œ μ‚¬μš©ν•  수 μžˆλŠ” 것은 κ΅¬ν˜„λœ BeanPropertyBindingResult 객체가 λœλ‹€.




μ°Έκ³  πŸ§™
- Spring AOP aop logging μ‚¬μš©λ²•
- μŠ€ν”„λ§ AOP (Spring AOP) 총정리 : κ°œλ…, ν”„λ‘μ‹œ 기반 AOP, @AOP
- Spring Boot AOP κ°œλ… 및 μ‚¬μš©λ²•
- Spring AOP PointCut ν‘œν˜„μ‹ 정리
- JoinPoint의 μ‚¬μš©

- μ—΄κ±°ν˜• ElementType
- Enum의 μ‚¬μš©λ²•

그리고 http://localhost:8000/

πŸ“’ μ†Œκ° 😢
이거 μ™„μ „ 인생 κ·Έ μž‘μ±„ . . .
그리고 μ§€κΈˆμ€ 더 놀고 싢은 λ‚˜

0개의 λŒ“κΈ€