오늘도 배우자!

귀찮음에 배움을 멀리하지 않기를...

Develop/Server

SpringBoot AOP 이해 - AOP(1)

리다양 2019. 11. 29. 22:38

안녕하세요~!! 날씨가 점점 쌀쌀해지고있네요ㅠㅠ 다들 감기 조심하세요!!

그럼 이번에도 한번 시작해볼까요!!!

 

이전 글에서 너무 많은 기능을 한번에 적다보니 어떻게 풀어나가야할지 고민을 많이했어요...

사실 사용법만 쉽고 간단하게 딱 알려주자 라는 마음으로 블로그를 시작했는데

이전 글에서는 쉽지도 간단하지도 않게 해버렸다는 생각에 후회가 좀 되더라구요ㅠㅠ

 

그래서 앞으로의 글에서 하나하나씩 천천히 풀어나가보려고 합니다!!!

 

1. AOP(Aspect Oriented Programming)란?

여러군데 흩어져 있는 공통 기능을 한곳에 모아서 관리하자! 라는 생각으로 하는 프로그래밍 방식입니다.

 

이해를 돕기 위해서 AOP를 사용하지 않은 경우를 살펴보겠습니다.

예를들어 게시판, 유저, 관리자의 기능을 담당하는 코드가 있을 때 공통기능을 Class로 빼내서 필요할 때마다

불러서 재활용성을 높였어도 위와 같이 코드내에 공통 기능1, 2 들이 중복되게 됩니다ㅠㅠ

 

그래서 저런 공통 기능을 또 따로 빼서 각 기능별로 중복을 줄이고 필요한 기능만 코드에 담아내고싶어지는데요

이것이 바로 AOP의 시작입니다.

 

만약에 공통기능을 따로 빼내서 관리를 한다면 아래와 같은 구성이 나오게 되고,

기존에는 공통기능 1과 2가 해당 클래스의 고유 기능(초록, 주황, 보라색으로 표시된 기능들)이 실행되기 전, 후에 실행되고 있었으니 다음과 같이 정리가 됩니다.

 

기존에는 각 클래스 별로 공통 기능이 2개씩 있었으니 다른 클래스가 100개 더 생긴다면 공통기능 2개를 100번씩

추가해야하니... 생각만해도 귀찮겠죠??.. 하지만 위와같이 따로 공통기능 1,2를 관리하고 필요할때 고유 기능(초록, 주황, 보라색)을 호출해서 사용하도록 하면 매우 편해짐을 예상할 수 있어요!!!

 

대충 감이 올듯말듯하니 빨리 코드가 보고싶어지는 시점이시죠??ㅎㅎ

 

빠르게 코드를 보여드리고싶지만 어떤걸 받아들일때 기능에 대해서 생각해보는게 중요하다고 생각해요

그래서 구현에 앞서 한번 생각해보겠습니다.

 

1) AOP를 사용하기 위해서 어떤 라이브러리가 필요하지 않을까?

2) 공통 기능을 구현한다면 이것을 어떻게 스프링부트에서 판단해서 알아서 실행시켜줄까?

3) 컨트롤러는 어노테이션붙이면 알아서 URL을 매핑해줬다.

4) AOP도 AOP관련 어노테이션 붙이면 알아서 실행해줄까?

 

요정도까지하고 진행을 해보도록하겠습니다.

 

2. Spring Boot AOP Dependency 추가

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

 

3. AOP 관련 클래스를 만들기위해 클래스(빈)를 하나 생성하고 @Aspect 어노테이션 붙이기

@Component
@Aspect
public class LoggerAspect {

}

 

4. 공통 기능을 작성하기

@Component
@Aspect
public class LoggerAspect {

	private Logger log = LoggerFactory.getLogger(this.getClass());

	@Around("execution(* com.example.demo.controller.*Controller.*(..))")
	public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
    	log.info("Before Execute Method!!!");
		Object proceed = joinPoint.proceed();
		log.info("After Execute Method!!!!");
		return proceed;
	}
}

갑자기 코드가 확나와서 놀라셨죠?? 하나하나 설명할것이니 걱정하지마세요!! 시작하겠습니다!!

 

1) @Component

이 클래스가 빈이라는 것을 나타내줍니다.(@Aspect라는 어노테이션안에는 @Contoller, @Service 이런 애들처럼

@Aspect라는 녀석이 @Component를 내부에 품고있지 않아요 ㅠㅠ 그래서 추가해줍니다.)

 

2) @Aspect

나는 AOP여!!! 하고 선언을 합니다. 그러면 스프링이 아 요녀석 AOP 관련 녀석이고만!! 하고 설정을 해줍니다.

 

3) @Around

공통기능이 어떤 기능 전에 로그를 찍는 것 일수도 있고, 어떤 기능 수행 후에 로그를 찍는 것 일수도 있는데

@Around라는 녀석은 이름을 보면 주변 두르고있는 느낌이 오지 않으시나효!!! 역시 대단하십니다!!

이녀석은 기능 실행 전, 후, 예외시 모든 시점에 적용됩니다!!!

 

그러니 이 어노테이션이 딱 달려있으면 아 어떤거 실행하기 전, 후 모두 다 관리하겠군!! 하고 생각이 들면

당신은 쵝오의 슾흐링 개발자!!

 

4) @Around("execution(* com.example.demo.controller.*Controller.*(..))")

execution(* com.example.demo.controller.*Controller.*(..)) 요 뜻을 한번 해석해볼게요!!

 

실행할꺼야( execution )

 

어떤 리턴타입이던 상관없이 모든 리턴타입의 메서드에 대해서!( execution(* )

 

com.example.demo.controller 패키지에 속해있는 이름이 Controller로 끝나는 모든 클래스의 메서드에 대해서!

( execution(* com.example.demo.controller.*Controller.*

 

그 메서드 들은 파라미터가 0개던 몇개던 상관없이 모든 메서드에 대해서 실행할꺼야

( execution(* com.example.demo.controller.*Controller.*(..)) )

 

execution(* com.example.demo.controller.*Controller.*(..)) 이 표현식은 어떤 객체에 포함된 메서드에 대해서

실행할지 결정하는 역할을 하는데요 메서드는 리턴타입이 void일수도 int일수도 Student와 같은 객체일수도 있고, 파라미터가 없을수도, 1개일수도, 2개일수도 있어요 그래서 특정 메서드에 대해서 실행하기 위해서는 다른 표현식이 필요한데 이부분은 나중에 다루도록 하겠습니다 ㅠㅠ

 

5) join.proceed()

이녀석이 아래 이미지에서 노란색에 해당하는 녀석입니다!!

즉, join.proceed() 앞뒤로 처리해야할 기능(로깅 등과 같은 기능)을 작성하면 앞으로

com.example.demo.controller 패키지의 이름이 Controller로 끝나는 객체의 모든 메서드가 실행될 때마다(execution(* com.example.demo.controller.*Controller.*(..)) ) joint.proceed() 앞뒤에 작성된 공통 기능들이 실행되게 됩니다. 

 

코드상에서는

log.info("Before Execute Method!!!");

Object proceed = joinPoint.proceed();

log.info("AfterExecute Method!!!");

요렇게 나왔으니 com.example.demo.controller 패키지 밑 컨트롤러 실행전Before Execute Method!!! 라는 로그가,

컨트롤러 실행후AfterExecute Method!!! 로그가 출력되게 되겠죠??ㅎㅎ

 

오늘은 이렇게 부트에서 간단하게 컨트롤러 실행 전, 후에 로그를 찍는 기능을 AOP를 이용하여 구현해보았습니다!!

다음시간에는 스프링 AOP 개념의 심화편을 한번 진행해보도록 할게요!!!

 

ps. 부족한 실력의 글이지만 응원해주시고 찾아주시는 분들께 너무 감사드려요!!