AOP(Aspect Oriented Programming)란 관점 지향 프로그래밍 기법이다. 어떤 관점으로 프로그래밍을 할까? 핵심로직이냐, 부가로직이냐가 바로 그 관점이다. 로직들을 핵심내용인지 부가내용인지에 대한 관점으로 나누고 나뉜 파트들 중 공통된 부분들은 하나로 묶어 모듈화시키는 기법이 바로 AOP다. 일반적으로 프로그래밍 언어들은 OOP(Object Oriented Programming)라는 객체 지향 프로그래밍 언어다. 로직을 객체 단위로 묶어서 개발하는 방식이고 일반적으로 이 방법이 가장 친근할 것이다. AOP는 이런 OOP와 상호보완 관계를 갖는다. 예제를 통해 확인해본다.
예제)
일반적인 OOP객체지향프로그래밍 클래스들과 구성내용
클래스A : 시작메시지, A만의 핵심로직, 끝메시지
클래스B : 시작메시지, B만의 핵심로직, 끝메시지
클래스C : 시작메시지, C만의 핵심로직, 끝메시지
AOP로 공통적인 부가기능을 Aspect라는 단위로 모듈화한다면?
클래스A : A만의 핵심로직
클래스B : B만의 핵심로직
클래스C : C만의 핵심로직
Aspect시작메시지 : 시작메시지
Aspect끝메시지 : 끝메시지
이렇게 핵심로직과 부가로직을 분리하여 재사용할 수 있게된다.
<!-- AOP 적용시에 필요한 추가 library - byte code를 실시간 동적으로 자동 생성해주는 기능의 library -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<!-- AOP 기능의 framework - spring이 AOP 기술을 활용해서 spring 스럽게 활용 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.3</version>
</dependency>
<!-- AOP 기능의 어노테이션 사용 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.30.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
...
</beans>
<!-- AOP기법 사용하겠다 -->
<aop:aspectj-autoproxy/>
<!-- 어노테이션 기능 사용하겠다 -->
<context:annotation-config/>
<!-- 어노테이션 기능을 위해 해당 package를 스캔해 component를 찾겠다 -->
<context:component-scan base-package="package명"/>
만약 어노테이션 기능을 쓰지 않는다면 다음과 같이 설정해준다.
<aop:config>
<aop:poincut> : expression="execution(**실행될 메서드,클래스 위치**)" / id="**해당포인트컷 id**"
<aop:aspect> : ref="**aspect로 쓸 bean id**"
<aop:after> : method="**실행시킬 aspect bean 속 메서드명**" / pointcut-ref="**실행시킬 포인트컷 id**"
<aop:before> : method="**실행시킬 aspect bean 속 메서드명**" / pointcut-ref="**실행시킬 포인트컷 id**"
<aop:after-returning> : method="**실행시킬 aspect bean 속 메서드명**" / pointcut-ref="**실행시킬 포인트컷 id**" / returning="**return한 값의 변수명**"
<aop:after-throwing> : method="**실행시킬 aspect bean 속 메서드명**" / pointcut-ref="**실행시킬 포인트컷 id**" / throwing="**throw한 예외의 변수명**"
<aop:aspect/>
<aop:poincut/>
<aop:config/>
해당 메서드의 url을 설정. 즉, view단에서 해당 메서드를 호출할 때 주소 설정
가변적인 url을 사용하면서 페이지자체는 같은 페이지를 보여주는 방식
@RequestMapping("uri주소") : uri주소값으로 중괄호를 이용해 가변적인 값을 표현한다.
ex) @RequsestMapping("abc/{changingValue}") 라면 abc/1, abc/999, abc/qwe 등등 모든 abc/ 이후 모든 값에 대한 uri를 호출할 경우 실행되는 메서드를 지정하는 모습이다. 하지만 abc/qwe/asd 같이 슬래쉬가 한 번더 생기는 경우는 실행되지 않는다. 다음과 같이 깊이가 깊어진 부분에 대한 가변적 uri처리를 하고 싶다면 @RequsestMapping("abc/{changingValue}/{chagingValue2}") 이런식으로 한 번더 처리해줘야 한다.
(@PathVariable String changingValue) : 바로 위 예제에서 {changingValue}로 가변적인 uri주소 부분을 표현했다. 이 가변적인 값을 변수로 받고 싶다면 메서드 파라미터 부분에 다음과 같이 해당 변수명으로 가변적인 uri주소값을 받을 수 있다.