[Spring AOP] 스프링 AOP 적용 예시, 실무 주의 사항
·
Spring/AOP
스프링 AOP - 실전 예제, 실무 주의 사항예제 만들기지금까지 학습한 내용을 활용해서 유용한 스프링 AOP를 만들어보자.@Trace 애노테이션으로 로그 출력하기@Retry 애노테이션으로 예외 발생시 재시도 하기로그 출력 AOP@Trace 가 메서드에 붙어 있으면 호출 정보가 출력되는 AOP를 만든다.@Slf4j@Aspectpublic class TraceAspect { @Before("@annotation(hello.aop.exam.annotation.Trace)") public void doTrace(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); log.info("[trace] {} args={}", jo..
[Spring AOP] 스프링 AOP - 포인트컷
·
Spring/AOP
스프링 AOP - 포인트컷애스펙트J는 포인트컷을 편리하게 표현하기 위한 특별한 표현식을 제공한다.포인트컷 지시자포인트컷 표현식은 execution 같은 포인트컷 지시자(Pointcut Designator)로 시작한다. 줄여서 PCD라 한다.포인트컷 지시자의 종류execution: 메소드 실행 조인 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하고, 기능도 복잡하다.within: 특정 타입 내의 조인 포인트를 매칭한다.args: 인자가 주어진 타입의 인스턴스인 조인 포인트this: 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트target: Target 객체(스프링 AOP 프록시가 가리키는 실제 대상)를 대상으로 하는 조인 포인트@target: 실행 객체의 클래스에 주어진 타입의..
[Spring AOP] 스프링 AOP 구현
·
Spring/AOP
스프링 AOP 구현프로젝트 생성Spring Web 의존성 사용 Ximplementation 'org.springframework.boot:spring-boot-starter-aop' 의존성 추가예제 프로젝트 만들기이전 챕터에서 사용했던 서비스 계층과 리포지토리 계층 코드랑 같음. 메서드 호출에 대한 로깅만 추가해주자.간단한 테스트@Slf4j@SpringBootTestpublic class AopTest { @Autowired OrderService orderService; @Autowired OrderRepository orderRepository; @Test void aopInfo() { log.info("isAopProxy, orderService={}",..
[Spring AOP] 스프링 AOP 개념
·
Spring/AOP
스프링 AOP 개념AOP 소개 - 핵심 기능과 부가 기능애플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있다. OrderService 초기 버전을 생각해보자.주문 로직을 실행하기 직전에 로그 추적 기능을 사용해야 하면, 핵심 기능인 주문 로직과 부가 기능인 로그 추적 로직이 하나의 객체 안에 섞여 들어가게 된다.부가 기능이 필요한 경우 이렇게 둘을 합해서 하나의 로직을 완성한다. 이제 주문 서비스를 실행하면 핵심 기능인 주문 로직과 부가 기능인 로그 추적 로직이 함께 실행된다.여러 곳에서 공통으로 사용하는 부가 기능보통 부가 기능은 여러 클래스에 걸쳐서 함께 사용된다. 예를 들어서 모든 애플리케이션 호출을 로깅 해야 하는 요구사항을 생각해보자. 이러한 부가 기능은 횡단 관심사(cross-cu..
[Spring AOP] @Aspect AOP
·
Spring/AOP
@Aspect AOP@Aspect 프록시 - 적용이전 챕터에서 Advisor를 직접 구현하여 스프링 빈으로 등록하면 스프링의 자동 프록시 생성기가 자동으로 처리해주는 것을 배웠다.스프링은 @Aspect 애노테이션으로 매우 편리하게 포인트컷과 어드바이스로 구성되어 있는 어드바이저 생성 기능을 지원한다.지금까지 어드바이저를 직접 만들었던 부분을 @Aspect 애노테이션을 사용해서 만들어보자.(@Aspect 는 관점 지향 프로그래밍(AOP)을 가능하게 하는 AspectJ 프로젝트에서 제공하는 애노테이션이다. 스프링은 이것을 차용해서 프록시를 통한 AOP를 가능하게 한다고 한다.)@Slf4j@Aspectpublic class LogTraceAspect { private final LogTrace logTr..
[Spring AOP] 빈 후처리기
·
Spring/AOP
빈 후처리기빈 후처리기 - 소개빈 후처리기 - BeanPostProcessor스프링이 빈 저장소에 등록할 목적으로 생성한 객체를 빈 저장소에 등록하기 직전에 조작하고 싶다면 빈 후처리기를 사용하면 된다.빈 후처리기 기능객체를 조작할 수도 있고, 완전히 다른 객체로 바꿔치기 하는 것도 가능하다. 빈 후처리기 - 예제 코드1public class BasicTest { @Test void basicConfig() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BasicConfig.class); //A는 빈으로 등록된다. A a = app..
[Spring AOP] 스프링이 지원하는 프록시
·
Spring/AOP
스프링이 지원하는 프록시이전 챕터에서 프록시 객체를 동적으로 만들어주는 동적 프록시 기술을 살펴보고, 그 한계점에 대해 살펴봤다.문제점인터페이스가 있는 경우에는 JDK 동적 프록시를 적용하고, 그렇지 않은 경우에는 CGLIB를 적용하려면 어떻게 해야할까?두 기술을 함께 사용할 때 부가 기능을 제공하기 위해 JDK 동적 프록시가 제공하는 InvocationHandler 와 CGLIB가 제공하는 MethodInterceptor 를 각각 중복으로 만들어서 관리해야 할까?특정 조건에 맞을 때 프록시 로직을 적용하는 기능도 공통으로 제공되었으면?위와 같은 문제점들을 해결할 수 있도록, 스프링은 ProxyFactory라는 기능을 제공하여 문제를 해결한다.프록시 팩토리 - 소개Q: 인터페이스가 있는 경우에는 JDK ..
[Spring AOP] 동적 프록시 기술
·
Spring/AOP
동적 프록시 기술프록시를 적용한 기존 코드에는 한 가지 문제점이 존재했다.대상 클래스 수 만큼 로그 추적을 위한 프록시 클래스를 만들어야 한다는 점이다로그 추적을 위한 프록시 클래스들의 소스코드는 거의 같은 모양을 하고 있다.리플렉션자바가 기본으로 제공하는 JDK 동적 프록시 기술이나 CGLIB 같은 프록시 생성 오픈소스 기술을 활용하면 프록시 객체를 동적으로 만들어낼 수 있다. 쉽게 이야기해서 프록시 클래스를 지금처럼 계속 만들지 않아도 된다는 것이다.JDK 동적 프록시는 자바 reflection 기술을 바탕으로 동작한다. 리플렉션과 관련된 내용은 스킵한다.JDK 동적 프록시소개앞선 예제에서 봤듯이 프록시의 로직은 같은데, 적용 대상만 차이가 있었다. 이 문제를 해결하는 것이 바로 동적 프록시 기술이다..
[Spring AOP] 프록시 패턴과 데코레이터 패턴
·
Spring/AOP
프록시 패턴과 데코레이터 패턴예제 프로젝트 생성v1 - 인터페이스와 구현 클래스 - 스프링 빈으로 수동 등록v2 - 인터페이스 없는 구체 클래스 - 스프링 빈으로 수동 등록v3 - 컴포넌트 스캔으로 스프링 빈 자동 등록실무에서 세 가지 경우를 모두 만날 수 있으므로, 세 가지 빈 등록 방식에 따른 프록시 패턴, 데코레이터 패턴의 적용에 대해 알아본다.예제의 기능은 이전 챕터에서의 상품 주문과 동일하다.예제 프로젝트 만들기 v1OrderControllerV1@RestControllerpublic interface OrderControllerV1 { @GetMapping("/v1/request") String request(@RequestParam("itemId") String itemId); ..
[Spring AOP] 템플릿 메서드 패턴과 콜백 패턴
·
Spring/AOP
템플릿 메서드 패턴과 콜백 패턴#Spring/고급템플릿 메서드 패턴 - 도입 배경이전 챕터에서는, 로그 추적기를 사용하기 위해 메서드 시그니처를 변경하는 것의 문제를 ThreadLocal을 통해 해결하였다.그런데 로그 추적기를 막상 프로젝트에 도입하려고 하니 문제점이 보인다.1~2줄짜리 비즈니스 로직이, 로그 추적기라는 부가 기능 때문에 코드가 엄청 늘어났다.//OrderControllerV0 코드@GetMapping("/v0/request")public String request(String itemId) { orderService.orderItem(itemId); return "ok";}//OrderControllerV3 코드@GetMapping("/v3/request")public Str..