[Spring] AOP(Aspect Oriented Programming)
AOP(Aspect Oriented Programming)란 관점 지향 프로그래밍을 뜻하는 용어로써 하나의 관점 혹은 관심사를 지정하고 관심사 전 후에 작업을 수행하게 만드는 프로그래밍 기법을 뜻한다.
예를 들어 특정 메서드 A를 관심사로 지정한 경우 A를 호출했을 때 A메서드가 실행되는 전과 후에 다른 작업을 끼워 넣는 것이다.
AOP는 로깅, 감사, 선언적 트랜잭션, 보안, 캐싱 등 다양한 곳에서 사용된다.
(1) AOP 관련 용어
- Joint Point : 모듈이 삽입되어 동작하게 되는 특정 위치(관심사)
- Point Cut : 다양한 Joint Point(관심사) 중에 어떤 것을 사용할지 선택
- Advice : Joint Point에 삽입되어 동작할 수 있는 코드
- Weaving : Advice를 핵심 로직 코드에 적용하는 것
- Aspect : Point Cut + Advice
(2) AOP Advice 종류
- before : 메서드 호출 전에 동작하는 Advice
- after-returning : 예외 없이 호출된 관심사의 동작이 완료되면 동작하는 Advice
- after-throwing : 호출된 관심사 동작 중 예외가 발생했을 때 동작하는 Advice
- after : 예외 여부 발생과는 상관없이 호출된 관심사의 동작이 완료되면 동작하는 Advice
- around : 관심사 호출 전과 후에 동작하는 Advice
(3) AOP 설정 (xml, @AspectJ)
AOP 설정하는 방법은 XML, @AspectJ 두 가지 방법이 있다.
1) xml으로 설정하는 방법
AOP 설정을 위해 라이브러리를 추가할 필요가 있다.
Maven Repository에서 Aspectj Weaver를 검색하여 라이브러리를 다운로드하여도 되고 필자가 올려놓은 코드를 사용해도 된다.
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<!-- Aspectj Weaver 1.9.5 최신 버전 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
xml파일을 이용하는 경우 네임스페이스를 추가해줄 필요가 있다.
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
위의 코드들을 xml파일에 beans 태그 안에 포함시켜준다. 첫 번째 라인의 코드는 xmlns: 가 있는 곳에 붙여 넣어준고 두 번째 세 번째 줄은 xsi:schemaLocation = 안에 붙여 넣어 준다.
다 붙여 넣어준 경우 아래와 같은 모습이 되게 끔 해준다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
<!-- aop -->
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<!-- aop -->
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
2) @AspectJ로 설정하는 방법
@AspectJ라는 Annotation을 이용하여 Advisor 역할을 할 Bean을 설정할 수 있다.
@AspectJ를 활용하기 위해서는 Bean 설정 파일에 따로 설정을 해주어야 한다.
Bean 설정 파일이 xml인 경우는 아래의 태그를 xml파일에 넣어준다.
<aop:aspectj-autoproxy/>
Bean 설정 파일이 자바 파일인 경우 아래의 Annotation을 빈 설정 파일 클래스 위에 설정해 준다.
@Configuration
@EnableAspectJAutoProxy
public class BeanConfigClass {
}
위의 설정을 해주었다면 @Aspect라는 Annotation이 있는 클래스를 분석하여 AOP기능을 활용할 수 있게 된다.
즉 xml파일에서 AOP 설정을 해주는 것이 아닌 Advisor 클래스에서 직접 AOP 기능을 세팅하여 사용할 수 있게 되므로 xml에 설정하는 것보다 편리하게 AOP기능을 사용할 수 있다.
자세한 설정 방법은 아래에서 다시 설명하도록 한다.
(4) AOP 관심사(Joint Point), Advice 설정
1) xml에 설정하는 방식
AOP 기능을 사용하기 위하여 관심사를 설정한다.
본 포스팅에서는 관심사를 메서드로 설정하였다.
public class TestBean {
// 관심사로 지정할 메서드
public void method1( ) {
System.out.println("method1 호출");
}
}
위의 코드처럼 클래스를 하나 만들어서 메서드를 만든다.
그리고 Advice 역할을 할 메서드들을 모아놓은 Advisor 클래스를 하나 만들어서 advice 메서드를 선언한다.
// Adsisor 클래스
public class AdvisorClass {
// advice - before
public void beforeMethod() {
System.out.println("beforeMehtod 호출");
}
// advice - after
public void afterMethod() {
System.out.println("afterMethod 호출");
}
// advice - around
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around 호출 1");
pjp.proceed();
System.out.println("around 호출 2");
}
}
여기서 주의할 점은 around 속성은 ProceedingJoinPoint타입을 매개변수로 받고 예외를 발생시킬 수 있으므로 Throwable을 throws 해주어야 한다.
around 속성은 관심사 앞 뒤로 호출이 되는 advice인데 관심사 전 후에 호출은 그 시기가 굉장히 까다롭다.
그래서 메서드에서 그 시기를 정해주는데 위 코드에서는 관심사 앞에 호출되게 설정한 동작이 System.out.println("around 호출 1");이고 pjp.proceed( ); 는 해당 관심사를 호출하는 코드이다.
관심사 호출 후 동작하는 코드는 위 코드에서 System.out.println("around 호출 2"); 로 설정하였다.
그 후 해당 관심사 클래스와 Advisor클래스를 빈으로 등록하고 메서드를 호출하는 행위를 관심사로 등록한다.
<bean id="xml1" class="kr.co.softcampus.beans.TestBean" />
<bean id="advisor1" class="kr.co.softcampus.advisor.AdvisorClass" />
<!-- aop 설정 -->
<aop:config>
<aop:aspect ref="advisor1">
<!-- 관심사 설정 -->
<aop:pointcut id="point1" expression="execution(* method1())" />
<!-- before 설정 -->
<aop:before method="beforeMethod" pointcut-ref="point1"/>
<!-- after 설정 -->
<aop:after method="afterMethod" pointcut-ref="point1"/>
<!-- around 설정 -->
<aop:around method="around" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
aop:config 태그를 선언한 후 그 안에 aop:aspect 태그를 선언하고 ref 값으로 Advisor클래스의 bean id값을 넣어준다.
aop:aspect 태그 안에는 aop 관련 설정들을 해준다. aop:pointcut 태그는 관심사를 설정해주는 태그로써 id 속성을 지정해주고 expression 속성에는 execution 속성을 이용하여 관심사를 설정한다.
execution 속성의 설정은 관심사로 설정한 메서드의 리턴 타입, 패키지, 클래스명, 메서드명( )이 들어가며 ( ) 소괄호 안에는 매개변수의 타입이 들어간다.
' * ' 애스터리스크는 하나의 모든 속성을 의미하며 '..' 은 0개부터 1개 이상의 모든 속성을 의미한다.
위의 코드에서 expression의 뜻은 모든 리턴 타입 모든 패키지 모든 클래스의 method1() 메서드를 관심사로 설정하겠다는 의미이다.
execution 표현식의 관한 설명은 아래 링크에 6.2.3.4. Examples를 참고하면 된다.
https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
Chapter 6. Aspect Oriented Programming with Spring
Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enabl
docs.spring.io
aop:before는 관심사 호출 전에 호출되는 작업으로 method 속성에는 AdvisorClass에서 설정한 before 메서드의 이름을 넣어주며 pointcut-ref에는 aop:pointcut에 id속성 값을 넣어준다.
aop:after는 관심사 호출 후에 호출되는 작업으로 method 속성에는 AdvisorClass에서 설정한 after 메서드의 이름을 넣어주며 pointcut-ref에는 aop:pointcut에 id속성 값을 넣어준다.
aop:around는 관심사 호출 앞 뒤에 호출되는 작업으로 method 속성에는 AdvisorClass에서 설정한 around 메서드의 이름을 넣어주며 pointcut-ref에는 aop:pointcut에 id속성 값을 넣어준다.
이 외에도 after-returning, after-throwing 등 여러 가지 속성이 있다.
2) @AspectJ Annotation을 이용하는 방식
(3) AOP 설정의 2) @AspectJ Anntation 설정을 하였다면 @Aspect를 이용하여 xml파일에 AOP 설정을 하지 않고 직접 Advisor 클래스에 AOP 설정을 할 수 있다.
// Advisor 클래스
@Aspect
@Component // Bean 자동 등록 Anntation으로 따로 xml파일이나 자바 Bean 설정파일에 설정을 세팅해주어야함
public class AdvisorClass {
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod 메서드 호출");
}
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod 메서드 호출");
}
@Around("execution(* method1())")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("aroundMethod 호출 1");
Object result = pjp.proceed();
System.out.println("aroundMethod 호출 2");
return result;
}
@AfterReturning("execution(* method1())")
public void afterReturning() {
System.out.println("afterReturning 호출");
}
}
위의 설명한 xml파일에 설정하는 방식보다 @AspectJ를 이용하는 편이 훨씬 간단한 것을 알 수 있을 것이다.
@Before 나 @After 같은 Advice Anntation에는 관심사를 설정하는 execution 속성이 들어가는데 이때 execution 표현식은 xml에서 설정할 때의 방법과 동일하다.
주의할 점은 Advisor 클래스나 관심사로 등록한 클래스는 IoC컨테이너에 Bean으로 등록이 되어 있어야 하는다는 점이다.
AOP 설정한 관심사를 실행하여 콘솔 로그를 확인해 보면 결과는 아래 사진과 같다.
around, before, 관심사, after, afterReturning메서드 모두 잘 호출되는 것을 확인 할 수 있다.
본 포스팅은 필자가 공부한 내용을 정리한 것으로 오류가 존재할 수 있습니다.
참고 : 인프런 - 스프링 프레임워크 개발자를 위한 실습을 통한 입문 과정