[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..
[Spring AOP] 쓰레드 로컬 - Thread Local
·
Spring/AOP
쓰레드 로컬 - Thread Local#Spring/고급예제 프로젝트 만들기 - V0일반적인 웹 애플리케이션에서 Controller → Service → Repository로 이어지는 흐름을 최대한 단순하게 구현@Repository@RequiredArgsConstructorpublic class OrderRepositoryV0 { public void save(String itemId) { //저장 로직 if (itemId.equals("ex")) { throw new IllegalStateException("예외 발생!"); } sleep(1000); } private void sleep(int millis) { ..
[Test] Mock(with Mockito)
·
Software Engineering/Test
가짜로 진짜를 테스트하기: Mock어드민 페이지에 '오늘 자 매출 통계 메일 전송' 기능을 추가한다고 해보자. 이 기능을 테스트하려면 OrderStatisticsService를 실행해야 한다.// OrderStatisticsService.javapublic boolean sendOrderStatisticsMail(LocalDate orderDate, String email) { // 1. 해당 일자의 결제완료된 주문들을 가져온다. // 2. 총매출 합계를 계산한다. // 3. 메일을 전송한다. boolean result = mailService.sendMail(..., email, ..., ...); if (!result) { throw new IllegalArgu..
[Test] Presentation Layer Test(with Spring Boot)
·
Software Engineering/Test
지금까지 Repository와 Service 계층을 통합 테스트하며 아래에서 위로 올라왔다. 드디어 외부 세계의 요청을 가장 먼저 마주하는 Presentation Layer(Controller) 에 도착했다.Controller를 테스트할 때는 이전과 다른 전략을 사용한다. 하위 계층(Service)은 이미 충분히 테스트했고 잘 동작한다고 가정하고, Controller의 책임에만 집중하는 것이다. 이를 위해 Mocking을 사용한다.Controller 테스트와 MockingMock은 말 그대로 '가짜' 객체다. Controller가 의존하는 Service를 가짜 객체로 대체하면, 우리는 Service의 실제 로직과 상관없이 Controller의 동작(요청 매핑, 파라미터 검증 등)만을 순수하게 테스트할 수..
[Test] Business Layer Test(with Spring Boot)
·
Software Engineering/Test
지난 글에서는 Persistence Layer를 테스트하며 기반을 다졌다. 이제 애플리케이션의 핵심, 비즈니스 로직을 구현하는 Business Layer(Service) 를 테스트해볼 차례다.Business Layer (Service) 테스트Service 계층은 Persistence Layer와 상호작용하며 비즈니스 로직을 전개하고, 트랜잭션을 보장해야 하는 아주 중요한 역할이다. 여기서는 하위 Repository 계층까지 아우르는 통합 테스트를 진행하며 TDD 방식으로 개발해보자.요구사항: 상품 번호 리스트를 받아 주문을 생성한다.TDD 사이클에 따라, 실패하는 테스트부터 작성한다.// OrderServiceTest.java@SpringBootTest@ActiveProfiles("test")class ..
[Test] Persistence Layer Test(with Spring Boot, JPA)
·
Software Engineering/Test
통합 테스트의 필요성지금까지 단위 테스트, TDD, 테스트를 문서로 활용하는 법까지 알아봤다. 그런데 실제 애플리케이션은 수많은 객체(모듈)들이 서로 협력하며 동작한다. A 모듈과 B 모듈이 만났을 때, 우리가 예상한 대로 잘 동작할까?이걸 확인하려면 통합 테스트가 필요하다. 단위 테스트만으로는 전체 기능의 신뢰성을 보장하기 어렵기 때문에, 우리는 풍부한 단위 테스트와 함께 큰 기능 단위를 검증하는 통합 테스트를 병행해야 한다.이번 시리즈에서는 스프링 부트의 계층형 아키텍처(Layered Architecture)에서 각 계층을 어떻게 테스트하는지 알아보자. 그 첫 번째 주자는 데이터를 책임지는 Persistence Layer다.Repository (Persistence Layer) 테스트Persisten..
[Test] 테스트는 '문서'다.
·
Software Engineering/Test
테스트는 [ 문서 ]다.테스트 코드를 단순히 프로덕션 코드를 검증하는 도구라고만 생각하면, 그 가치의 절반밖에 보지 못하는 것이다. 나는 테스트 코드가 곧 '살아있는 문서'라고 생각한다.테스트가 왜 문서가 될까?생각해보자. 우리는 항상 팀으로 일한다. 내가 짠 코드를 언젠가 다른 동료가 봐야 하고, 내가 과거에 했던 고민을 그 동료가 또 똑같이 할 필요는 없다.바로 이때 테스트 코드가 빛을 발한다.다양한 테스트 케이스는 프로덕션 코드의 기능과 정책을 설명하는 가장 정확한 설명서가 된다.과거에 누군가 했던 고민의 결과물을 팀의 자산으로 만들어준다.새로운 팀원이 들어왔을 때, 테스트 코드를 통해 시스템의 동작 방식을 빠르게 이해할 수 있다.결국 잘 짜인 테스트는 동료를 위한 가장 친절한 가이드가 된다.좋은 ..