CheerUp_Cheers

AOP 본문

스프링

AOP

meorimori 2021. 1. 28. 01:18

AOP의 특징?

1. 공통적인 처리.

2. 코드의 중복을 막고, 따로 관리가 가능

3. 관리가 용이(흐름의 앞, 중간, 뒤 처리가 가능).

 

# 들어가기전

[1] DispacherSevlet? Servlet

해당 어플리케이션에 들어오는 모든 요청을 핸들링

 -> 기존에는 web.xml에 등록

모든 요청을 Contorller로 보내 버리기 때문에, Css, Javasciprt등의 파일마저 가로챔

 -> 클라이언트의 요청을 2가지로 분리하여 구분하여 해결

   1) /apps의 URL로 접근시 디스패처 서블릿이 담당

   2) /resources의 URL로 접근시 담당 X

 

 

[2] HttpServletRequest(extended ServletRequest)

클라이언트의 요청과 관련된 정보와 동작을 가지는 객체

 -> 클라이언트 요청이 들어오면 WAS가 생성

 -> 요청정보의 있는 Path로 매핑된 서블릿에 전달

URL정보, 쿠키, 헤더, GET/POST로 전송한 값을 가져오는데 사용.

- 요청 파라미터 조회

- HttpSession 객체 조회

- request scope 상의 compponent간의 데이터 공유 지원

 

 

# AOP 말고도, 다른것(Filter, Interceptor)는 왜 안써?

[1] 일단, 세개는 실행되는 범위와 단위가 다르다.

[2] Interceptor와 Filter는 Servet단위이다 (얘네도 실행시점이 다르긴 함,).

 -> Filter는 Sevlet의 처리하기 전과 후를 다룸 ( + ServletRequest와 ServletResonse 교체를 가능 )

 -> Interceptor는 필터와 aop의 중간, HandlerMethod로 로직의 실행과 View 랜더링전에 추가작업 가능.

[3] 적용해야할 프로젝트의 구성에 적용하기가 힘들었다.

  -> 프로젝트의 디렉토리가 해당 도메인(주문, 로그인, 레디스...)등 안에 Controller와 Vo, Service가 있는 형태.

    각각의 도메인을 위한 Interceptor, Filter의 Mapping이 필요해 보였다. (몇일 간 찾아봐도 방법이 안보였다..)

    조사를 좀더 해보니 Interceptor로 흉내는 낼 수 있을거 같다..

 

# AOP를 그럼 왜써

AOP는 Asepect-Oriented Programming의 약자.

기능에 대한 관점으로 보며, 공통기능(다시 적용가능)과 핵심기능(변화가능)으로 나누는 것.

지금처럼 도메인별로 (Aspect)Contoller, Service들의 흩어져 있을 때, AOP를 사용하면 공통으로 처리가 가능할것 같았다.

- Concern (비슷한 부분), 아래 색칠된 부분

- Aspect가 기능들을 모아줄떄 사용.

- Advice는 해야할일, 기능

- PointCut은 어디에 적용 해야할지

- JoinPoint 끼어들 지점

# AOP의 적용방법

(!) 가정 : 메소드가 실행되기 전 Hello가 출력되길 원함.

1)Class A라는 Bean을 만들 때, A라는 타입의 프록시 Bean을 생성

 -> Spring Apllication의 Bean은 런타임으로 만듬.

2) 프록시 Bean은 실제 A의 메소드를 호출하기 전 Hello를 출력하고, A의 메소드 호출.

 

*Proxy 객체

본떠서 만든 객체라는 뜻으로, 행동을 똑같이함.

프록시가 진짜 객체를 채워준다( 바뀌는 것은 아니다 ).

 

프로젝트 적용 구상 아이디어

# AOP를 구상하게 된 발단

[1] 기존 API 요청들로 인한 Res, Req의 방대한 로그로 로그파일의 대용량화...

 -> 불필요하거나 가려야하는 request, respose를 설정의 필요성 대두.

[2] 각 API 요청마다 log.[debug|info].. 를 적는 비효율성

 -> 나중에 바꾸려면 일일이 Contoller로 가서 바꿔야 하나..?

 => [1], [2] 을 해결 하고 싶었다.

 

# 과정

[1] API로 찍히는 Log들 중, 불 필요한 Req, Res 찾기.

 - 직접 Log파일을 뒤져가면서, 자주 호출되거나 지나치다 싶은 요청들을 찾아다녔다.

 - 물론, 직접 Swagger-ui를 통해서 각각 찾고 다녀도 괜찮을거 같았다.

 

[2] 프로젝트 분석과 구상

 - 프로젝트에 어떤 기술을 적용할 지 분석

  구성이나~ 이미 사용된 기술이나~

 - Filter, Interceptor, AOP 중 선택

  위의 언급했던 것 처럼, 진행한 프로젝트에서는 AOP가 적합해 보였다.

 

[3] AOP config 생성 및 구성.

 - PointCut 설정(RequestMapping)

  물론 PostMapping/GetMapping/FatchMapping...등 많았지만, 각 Mapping마다 설정하는것에 대한 의문감으로, RequestMapping으로 설정하였다.

 - @Around 설정

 실제적으로 메소드가 실행되는 단이다. ( pjp.proceed() )

 메소드 실행 후, Response Log를 찍었다.

 - @Before 설정

 Param(Request Param)가 제대로 가져와 지지 않길래, @Before에서 가져왔고, 이쪽에서 Request Log를 찍었다.

 - @AfterThrowing 설정

 @Around에서 pjp.proceed()를 실행 시 오류가 발생한다

   1) 파라미터의 부족이나 이름이 맞지 않는다거나

   2) 결과의 실패

   3) 캐스팅 오류

    -> 이쪽에서 API 예외나 그 외의 예외를 처리와 Log를 찍어줌

 

[4] 핵심 로직 구성.

 - 위의 AOP Config의 구성이면, 일반적인 Log를 출력하는게 가능하다. 하지만, 기존의 Log는 레벨을 낮추고, 로그파일에 출력은 안하게 그대로 두고, 로그최적화가 필요한 vo만 건들고 싶었다.

 - 로그 최적화가 필요한 Vo에 인터페이스를 상속하게 하였다. 또한, 그 인터페이스는 로그용 Vo를 출력하는 메소드 가짐.

    -> 인터페이스는 어떠한 기능이 구현됨을 보장하기 떄문.

 - 로그용 Vo는 기존 Vo앞에 Log 문자를 삽입하는 형태로 생성.

  ex) LoginVo -> LoginLogVo

 - AOP Config에서 결과를 가져올 때, 해당(인터페이스) 인스턴스면 로그용 Vo를 출력하도록 함.

 

# 결과

 [1] 로그용 Vo 제작은 번거롭지 않음.

 [2] 기존 Vo에 인터페이스를 상속해서 가져온 뒤, 인터페이스의 메소드 구현이 번거로움.

 [3] 아직 진행중이라, 계속 시도해봐야함

 


참조

출처 : mangkyu.tistory.com/18

출처 : supawer0728.github.io/2018/04/04/spring-filter-interceptor/

출처 : velog.io/@max9106/Spring-AOP%EB%9E%80-93k5zjsm95

출처: https://goddaehee.tistory.com/154