0. 관점 지향 프로그래밍 (Aspect Oriented Programming)
웹 어플리케이션에서 로깅이나 보안 기능, 예외 처리나 이메일 전송 기능은 매우 자주 사용하는 기능이다. 하지만 프로젝트의 규모가 커지면 커질 수록 이러한 기능들을 하나하나 구현하기는 번거롭다.
관점 지향 프로그래밍(Aspect Oriented Programming)은 이러한 문제점을 해결하기 위한 개발론이다. 스프링의 AOP에서는 메서드 안의 주기능과 보조 기능을 분리하고 선택적으로 메서드에 적용해서 사용하는 개념이다.
스프링에서 AOP 기능을 구현하는 방법으로는 스프링에서 제공하는 API를 사용하는 방법과 애너테이션을 사용하는 방법이 있다.
* AOP 관련 용어
용어 | 설명 |
aspect | 구현하고자 하는 보조 기능을 의미 |
advice | aspect의 실제 구현체(클래스)를 의미. 메서드 호출을 기준으로 여러 지점에서 실행됨 |
joinpoint | advice를 적용하는 지점. 스프링은 method 결합점만 제공 |
pointcut | advice가 적용되는 대상을 지정. 패키지명/클래스명/메서드명을 정규식으로 지정하여 사용함 |
target | advice가 적용되는 클래스 |
weaving | advice를 주기능에 적용함 |
1. 스프링API를 이용한 AOP 기능 구현 과정
- 타깃(Target) 클래스를 지정한다.
- 어드바이스(Advice) 클래스를 지정한다.
- 설정 파일에서 포인트컷(Pointcut)을 설정한다.
- 설정 파일에서 어드바이스와 포인트컷을 결합하는 어드바이저(Advisor)를 설정한다.
- 설정 파일에서 스프링의 ProxyFactoryBean 클래스를 이용해 타깃에 어드바이스를 설정한다.
- getBean() 메서드로 빈 객체에 접근해 사용한다.
* 어드바이스(Advice) 인터페이스
인터페이스 | 추상 메서드 | 설명 |
MethodBeforeAdvice | void before(Method method, Object[] args, Object target) throws Throwable | 해당 메서드가 실행되기 전 실행 |
- Method method : 대상 객체에서 실행된 메서드를 나타내는 메서드 객체 - Object[] args : 메서드 인자 목록 - Object target : 대상 객체 |
||
AfterReturningAdvice | void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable | 해당 메서드가 실행된 후 수행 |
- Object returnValue : 대상 객체의 메서드가 반환하는 값 - Method method : 대상 객체에서 실행된 메서드를 나타내는 메서드 객체 - Object[] args : 메서드 인자 목록 - Object target : 대상 객체 |
||
ThrowsAdvice | void afterThrowing(Method method, Object[] args, Object target, Exception ex) | 해당 메서드에서 예외 발생 시 실행 |
- Method method : 대상 객체에서 실행된 메서드를 나타내는 메서드 객체 - Object[] args : 메서드 인자 목록 - Object target : 대상 객체 - Exception ex : 발생한 예외 타입 |
||
MethodInterceptor | Object invoke(MethodInvocation invocation) throws Throwable | 해당 메서드의 실행 전/후와 예외 발생 시 실행 |
- MethodInvocation invocation : 대상 객체의 모든 정보를 담고 있는 객체 (호출된 메서드, 인자 등) |
* 이 중 MethodInterceptor는 invoke() 메서드를 통해 다른 세 가지 인터페이스들의 동시에 수행할 수 있음
2. AOP 기능 구현해보기
1. XML 파일 생성
스프링에서 제공하는 API를 사용해 AOP를 적용하기 위해서는 XML 설정 파일을 생성해야한다. XML 파일의 전체적인 구성은 이전 게시글의 의존성 주입의 XML과 거의 같다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans
PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="calcTarget" class="com.spring.ex01.Calculator" /> <!-- 타겟 -->
<bean id="logAdvice" class="com.spring.ex01.LoggingAdvice" /> <!-- 어드바이스 -->
<!-- 타겟에 어드바이스를 설정 -->
<bean id="proxyCal" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="calcTarget" />
<property name="interceptorNames">
<list>
<value>logAdvice</value>
</list>
</property>
</bean>
</beans>
위의 구현 순서에도 나와있듯, 스프링 API를 사용해 AOP를 구현할 경우 ProxyFactoryBean 클래스를 사용해야 한다.
<bean> 태그를 통해 ProxyFactoryBean 클래스의 빈을 생성한 후, 내부에 사용할 Target 클래스, 그리고 사용할 Advice를 설정한다. 설정된 Target과 Advice 빈은 setter를 통해 ProxyFactoryBean의 빈에 주입된다.
<!-- 타깃에 어드바이스를 설정해주는 ProxyFactoryBean 클래스 -->
<bean id="proxyCal" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="calcTarget" /> <!-- 사용할 타겟 클래스 -->
<!-- 실행할 어드바이스 빈 설정 -->
<property name="interceptorNames">
<list>
<!-- 타깃 클래스에서 메서드가 호출될 때 실행할 어드바이스 빈 -->
<value>logAdvice</value>
</list>
</property>
</bean>
2. 어드바이스 클래스 작성
어드바이스 클래스에는 사용하고자 하는 Advice 인터페이스를 구현한다. 이번 실습의 경우 MethodInterceptor 인터페이스를 이용해 AOP 기능을 구현하고자 한다.
package com.spring.ex01;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggingAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("[메서드 호출 전 : LogginAdvice");
System.out.println(invocation.getMethod() + "메서드 호출 전");
Object object = invocation.proceed(); // 메서드 호출
System.out.println("[메서드 호출 후 : logginAdvice");
System.out.println(invocation.getMethod() + "메서드 호출 후");
return object;
}
}
MethodInterceptor 인터페이스의 경우 proceed()를 기준으로 그 앞에 작성된 내용을 메서드 호출 이전에 수행하게 되고, 그 뒤에 작성된 내용은 메서드 호출 이후에 수행하게 된다.
3. XML 파일 읽어오기 / 빈 생성
ApplicationContext를 통해 XML 파일을 읽어오고 빈을 생성할 수 있다. 특이한 점이라면 Target 클래스의 빈을 생성할 때 해당 클래스의 빈을 생성하는 것이 아닌 Advice 연결에 사용한 ProxyFactoryBean 클래스의 빈을 생성해 객체를 생성한다.
MethodInterceptor의 구현 클래스(Advice 클래스)에서 작성한 것과 같이 메서드 실행 전후로 작업이 수행되는 것을 알 수 있다.
'Java > Spring Framework' 카테고리의 다른 글
[Spring Framework] MyBatis 연동하기 (0) | 2023.01.19 |
---|---|
[Spring Framework] Eclipse 스프링 STS 설정하기 (0) | 2023.01.19 |
[Spring Framework] @RequestParam 과 @ModelAttribute (0) | 2023.01.15 |
[Spring Framework] 어노테이션을 이용한 페이지 구현 (0) | 2023.01.15 |
[Spring Framework] 의존성 주입 (Dependency Injection) (0) | 2023.01.11 |