Spring Framework의 3요소라 한다면 IoC/DI, AOP, PSA를 꼽는다. 이 세가지 요소를 알면 스프링을 넘어서 객체지향 개념에 도가 텄다고 할 정도로 심오한 내용들이다. 차근차근 알아보기로 하고 이 글에서는 AOP를 Spring boot에서 간단히 적용하는 방법에 대해서 살펴본다.
아래 링크는 스프링 공식홈에 있는 AOP에 관한 공식 설명이다. 읽기 싫은거 안다. 그래도 함 들여다 보기라도 하자.
AOP.. 풀어쓰면 Aspect Oriented Programming. 한글로 관점 지향 프로그래밍. 여기서 이해가 잘 안되는 단어는 물론 관점이다. 관점이 뭔지만 이해하면 AOP에 대한 개념은 확실히 잡힌다.
예를 들어 설명해본다. 회사에는 여러 부서가 있다. 개발팀.. 영업팀.. 기획팀.. 각 팀의 이름은 각 팀이 하는 일을 그대로 나타낸다. 하는 일의 "관점"으로 팀을 보았기 때문이다. 그런데 각 팀에서 하는 일은 그것뿐일까? 각 팀마다 총무가 있다고 가정해보자. 총무는 회식때마다 식당을 예약하고 사람들에게 공지를 하는 등 팀이 원래 하는 일과는 다른일을 한다. 그렇다면 원래 팀을 만들 때 총무팀을 만들고 총무들만 모아 놓아도 되는 거 아닐까?(사실 총무팀이 있긴 한데 회식에 관여하지는 않는다... --;;) 사실 회사의 중요한 일에 대한 관점으로 저렇게 나눠 놓은 것 뿐이다. 다른 관점으로 보면 총무만 모아놓고.. 한쪽에는 복사 하는 사람만 모아 놓아도 되는 것이다. 관점에 따라 다른것뿐이다.
이게 바로 관점이다. 다시 우리가 개발하는 쪽으로 돌아오면 총무가 로깅이나 트랜잭션 같은 얘들이다. 비지니스 로직과는 상관 없는데 항상 필요한 얘들. 그래서 메소드 마다 출현해서 코드 지저분하게 하는 얘들. 이런 얘들 좀 자동적으로 되면 참 좋을텐데라고 다들 생각해봤을거다.. 그런데 스프링은 프레임워크 차원에서 지원해준다. 그것도 쉽게.. 그리고 난 이 글에서 어떻게 쓰는지 설명한다.. 쉽게...해보자...
일단 소스 부터 보자.
이클립스 화면이다. 대충 설명하자면 LoggerAspect라는 aspect가 있고 하나의 Before Advice와 하나의 Aftger Advice가 있다. 두 개의 어드바이스는 com.v0o0v.comoncl package의 public method에 해당 코드를 실행한다.
위 말을 하나씩 설명하겠다. aspect는 말 그대로 관점이다. 사실 어드바이스 들이 모인 클래스라고 볼 수 있는데 이 클래스는 특정 관점에 대해서 만들것이기 때문에 클래스위에 @Aspect 붙여서 스프링한테 이거 aspect로 쓰시오... 이렇게 알려주는거다.
어드바이스는... 낑겨 들어가서 실행되는 코드 뭉치라고 보면 된다. 위에서 보면 로그를 출력해주는 부분이다.
이 어드바이스는 어디로(위? 아래?) 낑겨 들어가서 실행되는지가 중요한다 위에 보면 낑겨들어가기 전(before)과 낑겨들어갔다 나올때(after) 이다. 이 외에도 여러개가 있으니 여러분들이 직접 찾아보시라. 아.. 그리고 STS는 어드바이드 옆에 화살표가 자동으로 표시돼서 이게 어떤 어드바이스 인지 표시해준다. 그리고 이게 낑겨서 실행되는 조인포인트에도 화살표가 표시된다. 물론 방향은 어드바이스와 반대로 안으로 들어온다. STS쓰시다가 화살표가 뜨면.. 아 여기에 낑겨들어오는구나.. 이렇게 생각하시면 된다.
그리고 어디로 어떻게 낑겨 들어갈지 정해주는 것을 포인트 컷이라고 한다. 위에 보면
"execution(* com.v0o0v.comoncl..*.*(..))"
이 부분이다. 이건 위에 말했듯이 com.v0o0v.comoncl package의 public method면 낑겨 들어가라는 뜻인데 나름 여러가지 표현 방식이 있으니 이것도 찾아보시라들...
이제 스프링 빈즈 설정을 해야 하는데.. 스프링 같은 경우에는 <aop:aspectj-autoproxy/> 를 컨텍스트 세팅 파일에 추가해야하는데 스프링 부트 같은 경우에는 별다른 설정없이 그냥 된다.. 찾아 보지는 않았지만 기본으로 on이 되어 있지 않을까 한다.. 혹시 아시는 분 있으면 댓글 남겨주시라..
이제 실행하면 com.v0o0v.comoncl package 및 하부 패키지에 public으로 된 메소드 들은 call 될 때마다 어드바이스가 실행돼서 로그가 출력이 된다. 아래는 출력된 로그 샘플이다. 그냥 텍스트를 붙였더니 좀 지저분해 보이는 데 (중간에 이상한 코드들... [2m: 이런거... 스프링 부트는 로그에 색깔을 넣을 수 있는데 그거 지정해주는 코드로 보인다) start of method나 end of method로 찾아보시면 그 뒤에 클래스와 메소드 이름이 어떻게 찍히는지 보시면 된다..
2016-03-31 23:46:18.918[0;39m [32m INFO[0;39m [35m8040[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mication$$EnhancerBySpringCGLIB$$e436afd1[0;39m [2m:[0;39m Start Of Method class com.v0o0v.comoncl.ComonclApplication$$EnhancerBySpringCGLIB$$e436afd1 void com.v0o0v.comoncl.ComonclApplication.run(String[])
[2m2016-03-31 23:46:18.929[0;39m [32m INFO[0;39m [35m8040[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mcom.sun.proxy.$Proxy80 [0;39m [2m:[0;39m Start Of Method class com.sun.proxy.$Proxy80 Object org.springframework.data.repository.CrudRepository.save(Object)
Hibernate: insert into customer (customer_id, birthday, created_day, desc, name) values (null, ?, ?, ?, ?)
[2m2016-03-31 23:46:19.041[0;39m [32m INFO[0;39m [35m8040[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mcom.sun.proxy.$Proxy80 [0;39m [2m:[0;39m End Of Method class com.sun.proxy.$Proxy80 Object org.springframework.data.repository.CrudRepository.save(Object)
[2m2016-03-31 23:46:19.042[0;39m [32m INFO[0;39m [35m8040[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mcom.sun.proxy.$Proxy83 [0;39m [2m:[0;39m Start Of Method class com.sun.proxy.$Proxy83 Object org.springframework.data.repository.CrudRepository.save(Object)
Hibernate: insert into moim (moim_id, birthday, name) values (null, ?, ?)
[2m2016-03-31 23:46:19.050[0;39m [32m INFO[0;39m [35m8040[0;39m [2m---[0;39m [2m[ restartedMain][0;39m [36mcom.sun.proxy.$Proxy83 [0;39m [2m:[0;39m End Of Method class com.sun.proxy.$Proxy83 Object org.springframework.data.repository.CrudRepository.save(Object)