[TIL] 2024-08-13

성장일기·2024년 8월 17일

회고

목록 보기
28/37

중요 학습 내용 [Spring]

Spring

AOP

  • 핵심 관점(Primary Concern)을 proxy로 감싸 핵심 관점의 원본 코드와 관련없이 reflection을 활용하여 추가 기능(Advice)을 구현할 수 있다.

개념

  • Aspect: 핵심 비즈니스 로직과는 별도로 수행되는 횡단 관심사
  • Advice: Aspect의 기능
  • Joinpoint: Target Class의 메소드에서 Advice를 적용할 수 있는 지점들
  • Pointcut: 여러 joinpoint 중 advice를 적용할 곳을 지정한 것
    • 해당 조인포인트에서 어드바이스가 동작한다.
    • <포인트컷 표현식>
      • execution([수식어] 리턴타입 [클래스이름], 이름(파라미터))
      • [수식어]: public, private 등 수식어를 명시(생략 가능)
      • [리턴 타입]: 리턴 타입을 명시
      • [클래스 이름(패키지명 포함)] 및 메소드 이름: 클래스 이름과 메소드 이름을 명시
      • [파라미터(매개변수)]: 메소드의 파라미터를 명시
      • [" * "]: 1개이면서 모든 값이 올 수 있음
      • [" .. "]: 0개 이상의 모든 값이 올 수 있음
      • uses:
        • execution(public Integer [classpath].advice.*.*(*))
          • classpath...advice 패키지에 속해 있는 바로 다음 하위 클래스에 파라미터가 1개인 모든 메소드이자 접근 제어자가 public이고 반환형이 Integer인 경우
        • execution(* [classpath].annotation..stu*(..))
          • com.ongiraffens.section01.advice 패키지 및 하위 패키지에 속해 있고 이름이 stu로 시작하는 파라미터가 0개 이상인 모든 메소드이며 접근제어자와 반환형은 상관 없음
  • Weaving: Advice를 핵심 비즈니스 로직에 적용하는 것

활용

  • Transaction
  • Security
  • logging
  • monitoring performance
  • etc

적용 예시

[ContextConfiguration.java]

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // AOP 적용
public class ContextConfiguration {

}

[LoggingAspect.java]

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* claspath.aop.*Service.*(..))")
    public void logPointcut() {}

    // 설명. 1. Before Advice
//    @Before("execution(* [classpath].aop.*Service.*(..))")
    @Before("LoggingAspect.logPointcut()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before joinPoint.getTarget(): " + joinPoint.getTarget());
        System.out.println("Before joinPoint.getSignature: " + joinPoint.getSignature());
        if(joinPoint.getArgs().length > 0) {
            System.out.println("Before joinPoint.getArgs()[0]: " + joinPoint.getArgs()[0].getClass());
        }
    }

    // 설명. 2. After Advice
    @After("LoggingAspect.logPointcut()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After joinPoint.getTarget(): " + joinPoint.getTarget());
        System.out.println("After joinPoint.getSignature(): " + joinPoint.getSignature());
        if(joinPoint.getArgs().length > 0) {
            System.out.println("After joinPoint.getArgs()[0]: " + joinPoint.getArgs()[0]);
        }
    }

    // 설명. 3. AfterReturning Advice
    @AfterReturning(pointcut="logPointcut()", returning="result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("After Returning result: " + result);

        if (result != null && result instanceof List) {
            ((List<MemberDTO>) result).add(
                    new MemberDTO(3L, "반환 값 가공")
            );
        }
    }

    // 설명. 4. AfterThrowing Advice
    @AfterThrowing(pointcut="logPointcut()", throwing="exception")
    public void logAfterThrowing(Throwable exception) {
        System.out.println("After Throwing exception: " + exception);

    }

    // 설명. 5. Around Advice
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around Before: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();        // 타겟 메소드 동작
        System.out.println("Around After: " + joinPoint.getSignature().getName());
        System.out.println("result = " + result);
        return result;
    }

}

Reflection

개념

  • 컴파일 된 자바 코드에서 필드 및 메소드의 정보를 구해오는 방법
  • 스프링 프레임워크, 스프링 프레임워크, 마이바티스, 하이버네이트, Jackson 등의 라이브러리에서 사용
  • 스프링에서는 런타임 시 개발자가 등록한 빈을 애플리케이션 내부에서 다루기 위한 기술

주의사항

  • reflection은 강력한 도구이지만 무분별하게 사용해서는 안됨
    • 오버헤드 발생: 성능 저하를 발생할 수 있기 때문에 민감한 애플리케이션에서는 사용하지 않는다
    • 캡슐화 저해: private를 설정한 필드 또는 메소드에 접근 가능하기에 코드 기능이 저하. 해석이 어려워 여러가지 문제를 야기할 수 있다

Spring MVC 요청 처리 과정

  1. 클라이언트(웹 브라우저) 요청
    • 사용자가 웹 브라우저를 통해 HTTP 요청을 서버에 전송.
    • 요청은 URL, HTTP 메서드(GET, POST 등), 헤더, 바디 등을 포함
  2. DispatcherServlet
    • 역할: 모든 요청을 중앙에서 처리하는 서블릿 Spring MVC에서 모든 요청은 DispatcherServlet을 통해 전달
    • 동작: web.xml 또는 Spring Boot의 자동 설정에 의해 DispatcherServlet이 웹 애플리케이션에 등록됨
  3. HandlerMapping
    • 역할: 요청 URL에 매핑된 핸들러(컨트롤러)를 찾음
    • 동작: DispatcherServlet이 HandlerMapping을 사용하여 요청 URL과 매핑된 핸들러를 찾는다. 핸들러는 일반적으로 컨트롤러 메서드
  4. Controller
    • 역할: 비즈니스 로직을 처리하고, 요청을 처리하여 결과를 반환
    • 동작: 핸들러 매핑을 통해 찾은 컨트롤러 메서드가 호출됩니다. 메서드는 요청에 대한 처리를 수행하고, 처리 결과를 모델에 담아 반환합니다.
  5. ModelAndView
    • 역할: 컨트롤러가 반환하는 객체로, 뷰와 모델 데이터를 포함
    • 동작: 컨트롤러 메서드는 ModelAndView 객체를 반환하여 뷰 이름과 모델 데이터를 함께 전달. 모델 데이터는 뷰에서 사용될 수 있음
  6. ViewResolver
    • 역할: ModelAndView에서 전달된 뷰 이름을 실제 뷰(예: JSP 파일)로 변환
    • 동작: ViewResolver는 뷰 이름을 기반으로 실제 뷰를 찾고(prefix, suffix 적용), 뷰를 반환
  7. View Rendering
    • 역할: 모델 데이터를 사용하여 최종적인 HTML을 생성
    • 동작: View는 모델 데이터를 바탕으로 HTML 페이지를 렌더링한다. 이 과정에서 뷰 템플릿(JSP, Thymeleaf 등)이 사용된다.
  8. 클라이언트 응답
    • 역할: 최종적으로 생성된 HTML 페이지가 클라이언트에게 전송
    • 동작: View가 렌더링된 결과를 HTTP 응답으로 변환하여 클라이언트에게 반환
profile
엔지니어로의 성장일지

0개의 댓글