π AOP (κ΄μ μ§ν₯ νλ‘κ·Έλλ°)
π @μ΄λ
Έν
μ΄μ
μΌλ‘ AOP ꡬννκΈ°
π @Aspect / @Pointcut / @Around / @Before
πΎ λ©μλ μ€ν μ λ‘κ·Έ μ λ³΄κ° μΆλ ₯λλλ‘ νλ @μ΄λ
Έν
μ΄μ
πΎ μ ν¨μ± κ²μ¬ @μ΄λ
Έν
μ΄μ
'ν΅μ¬' κΈ°λ₯κ³Ό 'λΆκ°' κΈ°λ₯μ λλμ΄ κ°λ°νλλ‘ νλ κ².
μ£Ό λΉμ¦λμ€ λ‘μ§κ³Ό κ³΅ν΅ κΈ°λ₯μΌλ‘ ꡬλΆνκ³ , κ³΅ν΅ κΈ°λ₯μ νμν λ λΆλ¬μ μ μ©νλ€.
μ΄λ Έν μ΄μ 맨λ€μ΄μ AOP ꡬν
@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;
}
}
μ‘°μΈν¬μΈνΈλ λμ κ°μ²΄, λ©μλ λ° μ λ¬λλ νλΌλ―Έν°μ λν μ 보λ€( β λ‘μ§μ λΌμλ£μ μ μλ ν©λ₯ μ§μ μ΄ λ¨ )μ λͺ¨λ λ°°μ΄λ‘ κ°μ Έμ€λ κ°μ²΄μ΄λ€.
μ¦, 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 : ProceedingJoinPoint λ₯Ό κ°μ Έμ λ©μλ μ€νμ μ μ΄ν μ μλ€. μΌλ° JoinPointλ μ¬μ© κ°λ₯ν¨.
@Before : μ νμ²λ¦¬κ° μκ³ , μ΄λ Έν μ΄μ μ΄ λ¬λ¦° λ©μλ μ€ν μ μ AOP λ‘μ§μ μ€ννλ€. proceed() μμ.
BindingResult λ μΈν°νμ΄μ€λ‘, error μ 보λ₯Ό κ°μ§κ³ μλ κ°μ²΄μ΄λ€.
μΈν°νμ΄μ€μ΄κΈ° λλ¬Έμ, μ€μ μ¬μ©ν μ μλ κ²μ ꡬνλ BeanPropertyBindingResult κ°μ²΄κ° λλ€.
μ°Έκ³ π§
- Spring AOP aop logging μ¬μ©λ²
- μ€νλ§ AOP (Spring AOP) μ΄μ 리 : κ°λ
, νλ‘μ κΈ°λ° AOP, @AOP
- Spring Boot AOP κ°λ
λ° μ¬μ©λ²
- Spring AOP PointCut ννμ μ 리
- JoinPointμ μ¬μ©
- μ΄κ±°ν ElementType
- Enumμ μ¬μ©λ²
κ·Έλ¦¬κ³ http://localhost:8000/
π’ μκ° πΆ
μ΄κ±° μμ μΈμ κ·Έ μ‘μ± . . .
κ·Έλ¦¬κ³ μ§κΈμ λ λκ³ μΆμ λ